claude-dev-env 1.38.1 → 1.40.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 (282) hide show
  1. package/CLAUDE.md +10 -36
  2. package/_shared/pr-loop/audit-reply-template.md +147 -0
  3. package/_shared/pr-loop/fix-protocol.md +25 -4
  4. package/_shared/pr-loop/gh-payloads.md +37 -50
  5. package/_shared/pr-loop/scripts/code_rules_gate.py +0 -60
  6. package/_shared/pr-loop/scripts/config/post_audit_thread_constants.py +199 -0
  7. package/_shared/pr-loop/scripts/config/reviews_disabled_constants.py +8 -0
  8. package/_shared/pr-loop/scripts/post_audit_thread.py +1242 -0
  9. package/_shared/pr-loop/scripts/preflight.py +129 -2
  10. package/_shared/pr-loop/scripts/reviews_disabled.py +59 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -19
  12. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +1116 -0
  13. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +127 -0
  14. package/_shared/pr-loop/scripts/tests/test_preflight.py +41 -0
  15. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +36 -0
  16. package/_shared/pr-loop/state-schema.md +1 -1
  17. package/agents/clean-coder.md +2 -2
  18. package/agents/pr-description-writer.md +150 -52
  19. package/bin/install.mjs +6 -7
  20. package/bin/install.test.mjs +8 -0
  21. package/commands/doc-gist.md +16 -0
  22. package/commands/plan.md +0 -2
  23. package/commands/review-plan.md +1 -1
  24. package/docs/CODE_RULES.md +122 -2
  25. package/docs/PR_DESCRIPTION_GUIDE.md +127 -64
  26. package/hooks/blocking/bot_mention_comment_blocker.py +75 -0
  27. package/hooks/blocking/code_rules_enforcer.py +1143 -129
  28. package/hooks/blocking/convergence_gate_blocker.py +130 -0
  29. package/hooks/blocking/destructive_command_blocker.py +74 -0
  30. package/hooks/blocking/gh_body_arg_blocker.py +30 -0
  31. package/hooks/blocking/md_to_html_blocker.py +119 -0
  32. package/hooks/blocking/pr_description_enforcer.py +57 -22
  33. package/hooks/blocking/test_bot_mention_comment_blocker.py +131 -0
  34. package/hooks/blocking/test_code_rules_enforcer.py +21 -0
  35. package/hooks/blocking/test_code_rules_enforcer_any_exempt_files.py +70 -0
  36. package/hooks/blocking/test_code_rules_enforcer_any_imports_and_cast.py +92 -0
  37. package/hooks/blocking/test_code_rules_enforcer_banned_import_alias.py +143 -0
  38. package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +152 -0
  39. package/hooks/blocking/test_code_rules_enforcer_bare_except.py +120 -0
  40. package/hooks/blocking/test_code_rules_enforcer_boundary_types.py +175 -0
  41. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
  42. package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +50 -0
  43. package/hooks/blocking/test_code_rules_enforcer_docstring_format.py +255 -0
  44. package/hooks/blocking/test_code_rules_enforcer_inline_tuple_string_magic.py +130 -0
  45. package/hooks/blocking/test_code_rules_enforcer_stub_implementations.py +141 -0
  46. package/hooks/blocking/test_code_rules_enforcer_test_branching.py +143 -0
  47. package/hooks/blocking/test_code_rules_enforcer_thin_wrapper_files.py +169 -0
  48. package/hooks/blocking/test_code_rules_enforcer_todo_markers.py +99 -0
  49. package/hooks/blocking/test_code_rules_enforcer_typed_dict_pairs.py +141 -0
  50. package/hooks/blocking/test_convergence_gate_blocker.py +63 -0
  51. package/hooks/blocking/test_destructive_command_blocker.py +146 -0
  52. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +102 -0
  53. package/hooks/blocking/test_gh_body_arg_blocker.py +45 -0
  54. package/hooks/blocking/test_md_to_html_blocker.py +317 -0
  55. package/hooks/blocking/test_pr_description_enforcer.py +69 -8
  56. package/hooks/config/any_type_config.py +7 -0
  57. package/hooks/config/banned_identifiers_constants.py +11 -0
  58. package/hooks/config/blocking_check_limits.py +38 -0
  59. package/hooks/config/bot_mention_comment_blocker_constants.py +20 -0
  60. package/hooks/config/code_rules_enforcer_constants.py +53 -0
  61. package/hooks/config/convergence_branch_constants.py +9 -0
  62. package/hooks/config/doc_gist_auto_publish_constants.py +18 -0
  63. package/hooks/config/html_companion_constants.py +20 -0
  64. package/hooks/config/inline_tuple_string_magic_constants.py +22 -0
  65. package/hooks/config/pr_description_enforcer_constants.py +14 -0
  66. package/hooks/config/test_banned_identifiers_constants.py +17 -0
  67. package/hooks/hooks.json +28 -20
  68. package/hooks/pyproject.toml +69 -0
  69. package/hooks/validators/mypy_integration.py +47 -1
  70. package/hooks/validators/run_all_validators.py +3 -3
  71. package/hooks/validators/test_mypy_integration.py +50 -1
  72. package/hooks/workflow/doc_gist_auto_publish.py +144 -0
  73. package/hooks/workflow/md_to_html_companion.py +365 -0
  74. package/hooks/workflow/test_doc_gist_auto_publish.py +117 -0
  75. package/hooks/workflow/test_md_to_html_companion.py +452 -0
  76. package/package.json +1 -1
  77. package/rules/gh-body-file.md +2 -0
  78. package/scripts/Install-SweepEmptyDirs.ps1 +111 -0
  79. package/scripts/check.ps1 +106 -0
  80. package/scripts/config/timing.py +11 -0
  81. package/scripts/sweep_empty_dirs.py +138 -0
  82. package/scripts/sync_to_cursor/rules.py +1 -1
  83. package/scripts/test_sweep_empty_dirs.py +183 -0
  84. package/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +323 -0
  85. package/skills/_shared/pr-loop/scripts/_cli_utils.py +22 -0
  86. package/skills/_shared/pr-loop/scripts/_path_resolver.py +165 -0
  87. package/skills/_shared/pr-loop/scripts/_xml_utils.py +20 -0
  88. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +182 -0
  89. package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +185 -0
  90. package/skills/_shared/pr-loop/scripts/config/__init__.py +0 -0
  91. package/skills/_shared/pr-loop/scripts/config/path_resolver_constants.py +78 -0
  92. package/skills/_shared/pr-loop/scripts/init_loop_state.py +135 -0
  93. package/skills/_shared/pr-loop/scripts/teardown_worktrees.py +175 -0
  94. package/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +182 -0
  95. package/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +206 -0
  96. package/skills/bugteam/CONSTRAINTS.md +21 -22
  97. package/skills/bugteam/EXAMPLES.md +3 -3
  98. package/skills/bugteam/PROMPTS.md +227 -67
  99. package/skills/bugteam/SKILL.md +132 -455
  100. package/skills/bugteam/reference/README.md +1 -1
  101. package/skills/bugteam/reference/audit-and-teammates.md +112 -39
  102. package/skills/bugteam/reference/audit-contract.md +4 -22
  103. package/skills/bugteam/reference/copilot-gap-analysis.md +8 -5
  104. package/skills/bugteam/reference/design-rationale.md +2 -2
  105. package/skills/bugteam/reference/github-pr-reviews.md +50 -57
  106. package/skills/bugteam/reference/obstacles/audit-assign-ids.md +13 -0
  107. package/skills/bugteam/reference/obstacles/audit-capture-excerpts.md +13 -0
  108. package/skills/bugteam/reference/obstacles/audit-walk-categories.md +13 -0
  109. package/skills/bugteam/reference/obstacles/audit-write-xml.md +13 -0
  110. package/skills/bugteam/reference/obstacles/fix-append-summary.md +13 -0
  111. package/skills/bugteam/reference/obstacles/fix-apply-fixes.md +13 -0
  112. package/skills/bugteam/reference/obstacles/fix-git-add-commit.md +13 -0
  113. package/skills/bugteam/reference/obstacles/fix-git-push.md +13 -0
  114. package/skills/bugteam/reference/obstacles/fix-post-reply.md +13 -0
  115. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +13 -0
  116. package/skills/bugteam/reference/obstacles/fix-py-compile.md +13 -0
  117. package/skills/bugteam/reference/obstacles/fix-read-files.md +13 -0
  118. package/skills/bugteam/reference/obstacles/fix-resolve-thread.md +13 -0
  119. package/skills/bugteam/reference/obstacles/fix-test-suite.md +13 -0
  120. package/skills/bugteam/reference/obstacles/fix-violation-count.md +13 -0
  121. package/skills/bugteam/reference/obstacles/fix-write-xml.md +13 -0
  122. package/skills/bugteam/reference/team-setup.md +111 -9
  123. package/skills/bugteam/reference/teardown-publish-permissions.md +39 -8
  124. package/skills/bugteam/scripts/README.md +60 -0
  125. package/skills/bugteam/scripts/_claude_permissions_common.py +358 -0
  126. package/skills/bugteam/scripts/bugteam_code_rules_gate.py +976 -0
  127. package/skills/bugteam/scripts/bugteam_fix_hookspath.py +375 -0
  128. package/skills/bugteam/scripts/bugteam_preflight.py +328 -0
  129. package/skills/bugteam/scripts/config/bugteam_code_rules_gate_constants.py +25 -0
  130. package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +26 -0
  131. package/skills/bugteam/scripts/config/bugteam_preflight_constants.py +35 -0
  132. package/skills/bugteam/scripts/config/claude_permissions_common_constants.py +20 -0
  133. package/skills/bugteam/scripts/config/probe_code_rules_enforcer_check_constants.py +12 -0
  134. package/skills/bugteam/scripts/config/windows_safe_rmtree_constants.py +7 -0
  135. package/skills/bugteam/scripts/grant_project_claude_permissions.py +175 -0
  136. package/skills/bugteam/scripts/probe_code_rules_enforcer_check.py +107 -0
  137. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +220 -0
  138. package/skills/bugteam/scripts/test__claude_permissions_common.py +112 -0
  139. package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +400 -0
  140. package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +384 -0
  141. package/skills/bugteam/scripts/test_bugteam_preflight.py +309 -0
  142. package/skills/bugteam/scripts/test_claude_permissions_common.py +195 -0
  143. package/skills/bugteam/scripts/test_grant_project_claude_permissions.py +55 -0
  144. package/skills/bugteam/scripts/test_probe_code_rules_enforcer_check.py +76 -0
  145. package/skills/bugteam/scripts/test_revoke_project_claude_permissions.py +55 -0
  146. package/skills/bugteam/scripts/test_windows_safe_rmtree.py +108 -0
  147. package/skills/bugteam/scripts/windows_safe_rmtree.py +100 -0
  148. package/skills/bugteam/test_skill_additions.py +1 -11
  149. package/skills/code/SKILL.md +176 -0
  150. package/skills/copilot-review/SKILL.md +16 -0
  151. package/skills/doc-gist/SKILL.md +99 -0
  152. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +453 -0
  153. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +515 -0
  154. package/skills/doc-gist/references/examples/03-code-review-pr.html +638 -0
  155. package/skills/doc-gist/references/examples/04-code-understanding.html +491 -0
  156. package/skills/doc-gist/references/examples/05-design-system.html +629 -0
  157. package/skills/doc-gist/references/examples/06-component-variants.html +605 -0
  158. package/skills/doc-gist/references/examples/07-prototype-animation.html +455 -0
  159. package/skills/doc-gist/references/examples/08-prototype-interaction.html +396 -0
  160. package/skills/doc-gist/references/examples/09-slide-deck.html +592 -0
  161. package/skills/doc-gist/references/examples/10-svg-illustrations.html +492 -0
  162. package/skills/doc-gist/references/examples/11-status-report.html +528 -0
  163. package/skills/doc-gist/references/examples/12-incident-report.html +596 -0
  164. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +395 -0
  165. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +381 -0
  166. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +368 -0
  167. package/skills/doc-gist/references/examples/16-implementation-plan.html +702 -0
  168. package/skills/doc-gist/references/examples/17-pr-writeup.html +595 -0
  169. package/skills/doc-gist/references/examples/18-editor-triage-board.html +573 -0
  170. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +663 -0
  171. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +722 -0
  172. package/skills/doc-gist/references/examples/README.md +5 -0
  173. package/skills/doc-gist/scripts/config/__init__.py +0 -0
  174. package/skills/doc-gist/scripts/config/gist_upload_constants.py +16 -0
  175. package/skills/doc-gist/scripts/gist_upload.py +177 -0
  176. package/skills/doc-gist/scripts/test_gist_upload.py +51 -0
  177. package/skills/findbugs/SKILL.md +96 -2
  178. package/skills/monitor-open-prs/SKILL.md +14 -32
  179. package/skills/monitor-open-prs/test_skill_contract.py +0 -11
  180. package/skills/pr-consistency-audit/SKILL.md +112 -0
  181. package/skills/pr-consistency-audit/reference/detection-rules.md +96 -0
  182. package/skills/pr-consistency-audit/reference/illustrations.md +78 -0
  183. package/skills/pr-converge/SKILL.md +229 -23
  184. package/skills/pr-converge/config/__init__.py +0 -0
  185. package/skills/pr-converge/config/constants.py +63 -0
  186. package/skills/pr-converge/reference/convergence-gates.md +138 -44
  187. package/skills/pr-converge/reference/examples.md +43 -11
  188. package/skills/pr-converge/reference/fix-protocol.md +6 -5
  189. package/skills/pr-converge/reference/ground-rules.md +5 -3
  190. package/skills/pr-converge/reference/multi-pr-orchestration.md +44 -19
  191. package/skills/pr-converge/reference/obstacles/fix-post-replies.md +13 -0
  192. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +13 -0
  193. package/skills/pr-converge/reference/obstacles/fix-push.md +13 -0
  194. package/skills/pr-converge/reference/obstacles/fix-read-filelines.md +13 -0
  195. package/skills/pr-converge/reference/obstacles/fix-reset-state.md +13 -0
  196. package/skills/pr-converge/reference/obstacles/fix-resolve-threads.md +13 -0
  197. package/skills/pr-converge/reference/obstacles/fix-spawn-clean-coder.md +13 -0
  198. package/skills/pr-converge/reference/obstacles/fix-stage-commit.md +13 -0
  199. package/skills/pr-converge/reference/obstacles/fix-trigger-bugbot.md +13 -0
  200. package/skills/pr-converge/reference/obstacles/fix-write-test.md +13 -0
  201. package/skills/pr-converge/reference/per-tick.md +107 -31
  202. package/skills/pr-converge/reference/state-schema.md +22 -1
  203. package/skills/pr-converge/reference/stop-conditions.md +9 -7
  204. package/skills/pr-converge/scripts/README.md +34 -46
  205. package/skills/pr-converge/scripts/check_bugbot_ci.py +279 -0
  206. package/skills/pr-converge/scripts/check_convergence.py +497 -0
  207. package/skills/pr-converge/scripts/check_pending_reviews.py +154 -0
  208. package/skills/pr-converge/scripts/config/pr_converge_constants.py +118 -0
  209. package/skills/pr-converge/scripts/fetch_copilot_reviews.py +134 -0
  210. package/skills/pr-converge/scripts/post_fix_reply.py +168 -0
  211. package/skills/pr-converge/scripts/test_check_bugbot_ci.py +312 -0
  212. package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -12
  213. package/skills/qbug/SKILL.md +157 -27
  214. package/skills/session-log/SKILL.md +216 -114
  215. package/skills/session-tidy/SKILL.md +1 -1
  216. package/skills/skill-builder/SKILL.md +138 -56
  217. package/skills/skill-builder/references/delegation-map.md +72 -113
  218. package/skills/skill-builder/references/progressive-disclosure.md +122 -0
  219. package/skills/skill-builder/references/self-audit-checklist.md +92 -0
  220. package/skills/skill-builder/references/skill-types.md +228 -0
  221. package/skills/skill-builder/references/thariq-x-post-skills.json +33 -0
  222. package/skills/skill-builder/templates/gap-analysis.md +15 -8
  223. package/skills/skill-builder/workflows/improve-skill.md +86 -57
  224. package/skills/skill-builder/workflows/new-skill.md +80 -168
  225. package/skills/skill-builder/workflows/polish-skill.md +78 -54
  226. package/skills/structure-prompt/SKILL.md +50 -0
  227. package/skills/structure-prompt/reference/adversarial-tuning.md +62 -0
  228. package/skills/structure-prompt/reference/block-classification.md +27 -0
  229. package/skills/structure-prompt/reference/canonical-case.md +48 -0
  230. package/skills/structure-prompt/reference/citation-depth.md +70 -0
  231. package/skills/structure-prompt/reference/cleanup.md +33 -0
  232. package/skills/structure-prompt/reference/constraints.md +33 -0
  233. package/skills/structure-prompt/reference/directives.md +37 -0
  234. package/skills/structure-prompt/reference/examples.md +72 -0
  235. package/skills/structure-prompt/reference/instantiation.md +51 -0
  236. package/skills/structure-prompt/reference/output-contract.md +72 -0
  237. package/skills/structure-prompt/reference/per-category.md +23 -0
  238. package/skills/structure-prompt/reference/persona.md +38 -0
  239. package/skills/structure-prompt/reference/research.md +33 -0
  240. package/skills/structure-prompt/reference/structure.md +28 -0
  241. package/agents/code-standards-agent.md +0 -93
  242. package/agents/groq-coder.md +0 -113
  243. package/agents/plan-executor.md +0 -226
  244. package/agents/project-docs-analyzer.md +0 -53
  245. package/agents/project-structure-organizer-agent.md +0 -72
  246. package/agents/skill-to-agent-converter.md +0 -370
  247. package/agents/skill-writer-agent.md +0 -470
  248. package/agents/user-docs-writer.md +0 -67
  249. package/agents/workflow-visual-documenter.md +0 -82
  250. package/commands/readability-review.md +0 -20
  251. package/hooks/mypy.ini +0 -2
  252. package/hooks/notification/attention_needed_notify.py +0 -71
  253. package/hooks/notification/claude_notification_handler.py +0 -67
  254. package/hooks/notification/notification_utils.py +0 -267
  255. package/hooks/notification/subagent_complete_notify.py +0 -381
  256. package/hooks/notification/test_attention_needed_notify.py +0 -47
  257. package/hooks/notification/test_claude_notification_handler.py +0 -54
  258. package/hooks/notification/test_notification_utils.py +0 -91
  259. package/hooks/notification/test_subagent_complete_notify.py +0 -79
  260. package/scripts/config/groq_bugteam_config.py +0 -230
  261. package/scripts/config/test_groq_bugteam_config.py +0 -83
  262. package/scripts/config/test_spec_implementer_prompt.py +0 -32
  263. package/scripts/groq_bugteam.README.md +0 -131
  264. package/scripts/groq_bugteam.py +0 -647
  265. package/scripts/groq_bugteam_dotenv.py +0 -40
  266. package/scripts/groq_bugteam_spec.py +0 -226
  267. package/scripts/test_groq_bugteam.py +0 -529
  268. package/scripts/test_groq_bugteam_apply_fix_from_spec.py +0 -426
  269. package/scripts/test_groq_bugteam_dotenv.py +0 -66
  270. package/scripts/test_groq_bugteam_spec.py +0 -338
  271. package/skills/bugteam/SKILL_EVALS.md +0 -309
  272. package/skills/dream/SKILL.md +0 -118
  273. package/skills/ingest/SKILL.md +0 -40
  274. package/skills/npm-creator/SKILL.md +0 -187
  275. package/skills/readability-review/SKILL.md +0 -127
  276. package/skills/resume-review/SKILL.md +0 -261
  277. package/skills/rule-audit/SKILL.md +0 -307
  278. package/skills/rule-creator/SKILL.md +0 -150
  279. package/skills/searching-obsidian-vault/SKILL.md +0 -131
  280. package/skills/skill-writer/REFERENCE.md +0 -284
  281. package/skills/skill-writer/SKILL.md +0 -222
  282. package/skills/tdd-team/SKILL.md +0 -128
@@ -1,5 +1,82 @@
1
1
  # Gate, cycle, AUDIT, and FIX
2
2
 
3
+ ## Pre-cycle: walk prior bugteam reviews end-first
4
+
5
+ **Pre-cycle: walk prior bugteam reviews end-first** (once per PR, after Step 2
6
+ and before iteration begins, when `last_action == "fresh"`). A re-invocation of
7
+ `/bugteam` on a PR with prior loops detects whether the most recent loop already
8
+ cleaned this HEAD (short-circuit) and otherwise records that prior loops were
9
+ dirty so the AUDIT runs against the latest diff with that signal in mind:
10
+
11
+ ```python
12
+ dirty_review_count = 0
13
+ all_reviews = pull_request_read(
14
+ method="get_reviews", pullNumber=N, owner=O, repo=R
15
+ )
16
+
17
+ NEW_BUGTEAM_HEADER_PREFIX = "**Bugteam audit completed**"
18
+ LEGACY_BUGTEAM_HEADER_PREFIX = "## /bugteam loop "
19
+ NEW_CLEAN_STATE_LABEL = "Clean — no findings"
20
+ LEGACY_CLEAN_TOKEN = "→ clean"
21
+
22
+
23
+ def is_bugteam_review(review_body: str) -> bool:
24
+ return (
25
+ review_body.startswith(NEW_BUGTEAM_HEADER_PREFIX)
26
+ or review_body.startswith(LEGACY_BUGTEAM_HEADER_PREFIX)
27
+ )
28
+
29
+
30
+ def is_clean_bugteam_review(review_body: str) -> bool:
31
+ if review_body.startswith(NEW_BUGTEAM_HEADER_PREFIX):
32
+ return NEW_CLEAN_STATE_LABEL in review_body.splitlines()[0]
33
+ return review_body.rstrip().endswith(LEGACY_CLEAN_TOKEN)
34
+
35
+
36
+ prior_reviews = [
37
+ rev for rev in all_reviews
38
+ if is_bugteam_review(rev.get("body", ""))
39
+ ]
40
+ prior_reviews.sort(key=lambda rev: rev["submitted_at"], reverse=True)
41
+ ```
42
+
43
+ The classifier handles both shapes. The new shape — emitted by
44
+ `_shared/pr-loop/scripts/post_audit_thread.py` reading
45
+ `_shared/pr-loop/audit-reply-template.md` at runtime — opens with
46
+ `**Bugteam audit completed** —— Clean — no findings` on CLEAN and
47
+ `**Bugteam audit completed** —— Findings requested` on DIRTY. The legacy
48
+ shape — emitted before `post_audit_thread.py` became canonical — opens
49
+ with `## /bugteam loop <N> audit:` and ends with `→ clean` on CLEAN. Both
50
+ shapes are recognized so re-invocations on long-lived branches with
51
+ mixed-shape history classify correctly.
52
+
53
+ Iterate from index 0 (most recent) toward older entries:
54
+
55
+ - A bugteam review body whose first line carries the
56
+ `Clean — no findings` state label (new shape) or whose body ends with
57
+ `→ clean` (legacy shape) is **clean**; any other bugteam review body
58
+ is **dirty**.
59
+ - For a dirty review, increment `dirty_review_count` by one. The review's
60
+ specific finding bodies are not carried forward —
61
+ bugteam's AUDIT regenerates
62
+ findings against the current HEAD's diff each loop, so prior bodies are stale
63
+ by definition. The count alone is the carried signal.
64
+ - Stop at the first clean review. Older reviews are presumed addressed at that
65
+ clean checkpoint and are not re-read.
66
+ - When index 0 is itself clean AND its `commit_id` matches `git rev-parse HEAD`,
67
+ the PR is already converged on this HEAD — set `last_action="audited"`,
68
+ `last_findings='{"total": 0}'`, fall through to step 1's `converged` exit,
69
+ skip Step 3 iteration entirely.
70
+ - When `dirty_review_count > 0`, log the count and proceed into the normal
71
+ iteration; the next AUDIT regenerates anchored findings against the current
72
+ HEAD so `loop_comment_index` stays correct. Unlike `pr-converge` — where
73
+ Cursor Bugbot's prior dirty-review *bodies* are read back by the Fix protocol
74
+ because each dirty body lists specific findings the loop must still address
75
+
76
+ bugteam's per-loop bodies are anchored to the diff at *that loop's* HEAD, so
77
+ re-applying them against a newer diff would be incorrect. The count is
78
+ sufficient signal that "prior loops did not converge here."
79
+
3
80
  ## Step 3 — The cycle (full detail)
4
81
 
5
82
  Repeat until an exit condition fires.
@@ -22,12 +99,12 @@ Repeat until an exit condition fires.
22
99
  `git merge-base` + `git diff --name-only` live inside the script; see [`../../../_shared/pr-loop/scripts/README.md`](../../../_shared/pr-loop/scripts/README.md) for what lives under this directory, and [`../../../_shared/pr-loop/code-rules-gate.md`](../../../_shared/pr-loop/code-rules-gate.md) for gate-only merge-base / invocation semantics. The lead runs this (not a teammate).
23
100
 
24
101
  2. If exit code **0** → continue to step 2.5 (AUDIT spawn) below.
25
- 3. If exit code **non-zero** → spawn a new **clean-coder** teammate — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
26
- 4. After gate exit **0**, increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached` (counts **audits**, not standards-only rounds).
102
+ 3. If exit code **non-zero** → spawn a new **clean-coder** teammate (`mode="bypassPermissions"`) — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
103
+ 4. After gate exit **0**, increment `loop_count`. If `loop_count > 20`, exit reason = `cap reached` (counts **audits**, not standards-only rounds).
27
104
  5. Execute **AUDIT action** (spawn bugfind). Print progress: `Loop <L> audit: ...`
28
105
 
29
106
  3. **FIX path** (when `last_action == "audited"` and `last_findings.total > 0`):
30
- 1. Increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached`.
107
+ 1. Increment `loop_count`. If `loop_count > 20`, exit reason = `cap reached`.
31
108
  2. Execute **FIX action** (spawn bugfix clean-coder for audit findings). Print: `Loop <L> fix: commit ...`
32
109
  3. Set `last_action = "fixed"`, update `audit_log`, loop to step 1 (next iteration hits **pre-audit path** before the next AUDIT).
33
110
 
@@ -37,53 +114,47 @@ Repeat until an exit condition fires.
37
114
 
38
115
  **Note:** The first iteration uses **pre-audit path** then **AUDIT**. After a **FIX**, the next iteration runs **pre-audit path** again (gate → then AUDIT), so `validate_content` stays green before semantic audit.
39
116
 
40
- ## AUDIT action (clean-room teammate, fresh per loop)
41
-
42
- Capture a fresh PR diff for this loop into the per-PR scoped directory so concurrent `/bugteam` runs keep patches isolated. Use the literal `<run_temp_dir>` resolved once in Step 2 — Claude resolves the absolute path; every shell receives the same literal value.
117
+ ## AUDIT action
43
118
 
44
- Commands and `Agent(...)` shape: `SKILL.md`.
119
+ Spawn one audit agent that walks all A–K categories:
45
120
 
46
- `<run_temp_dir>` includes the sanitized `team_name` and timestamp; `team_name` is already prefixed with `bugteam-`. Claude resolves `Path(tempfile.gettempdir()) / team_name` once and passes that absolute path to every shell. `tempfile.gettempdir()` honors `TMPDIR`, `TEMP`, `TMP` and falls back to the OS temp directory, so the same approach works on macOS, Linux, Windows cmd.exe, and PowerShell.
47
-
48
- Each loop calls `Agent` again with a fresh invocation so the teammate starts with its own context window. Doc line on lead history: [`../sources.md`](../sources.md).
49
-
50
- See [`../PROMPTS.md`](../PROMPTS.md) for AUDIT spawn-prompt XML and bugfind outcome schema. Substitute placeholders (`repo`, `branch`, `base_branch`, `pr_url`, `loop`, `diff_path`) into the `prompt` argument.
51
-
52
- After the teammate returns, the lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml` from the worktree directory with the `Read` tool, parses it, and populates `loop_comment_index` from `<finding>` elements.
53
-
54
- ### Shutdown (bugfind)
121
+ ```
122
+ Agent(
123
+ subagent_type="code-quality-agent",
124
+ name="bugfind-pr<N>-loop<L>",
125
+ model="opus",
126
+ run_in_background=true,
127
+ description="Audit {owner}/{repo}#{N} loop {L}",
128
+ prompt="<output of build_audit_prompt.py; see ../../_shared/pr-loop/scripts/build_audit_prompt.py>"
129
+ )
130
+ ```
55
131
 
56
- Teammates self-terminate when complete — the background-completion notification arrives and the lead reads the outcomes XML. If the notification does not arrive within the lead timeout (120s), treat as a hard blocker and abort the loop.
132
+ The audit prompt XML is emitted by
133
+ [`build_audit_prompt.py`](../../_shared/pr-loop/scripts/build_audit_prompt.py).
134
+ Run it with `--owner --repo --pr-number --loop --head-ref --base-ref --worktree-path --run-temp-dir`
135
+ to generate the complete `<spawn_prompt>` XML on stdout.
57
136
 
58
137
  `last_action = "audited"`. Append audit metadata to `audit_log`.
59
138
 
60
- ### Parallel auditors (`loop_count >= 4`)
139
+ ## FIX action (fresh teammate)
61
140
 
62
- The pre-audit gate must pass immediately before this step. After three full audit/fix rounds without convergence, issue eleven `Agent` calls in **one** assistant message so they run in parallel:
141
+ Spawn:
63
142
 
64
143
  ```
65
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-a", team_name="<team_name>", model="opus", run_in_background=true, description="Bugfind audit PR <N> loop <L> validator", prompt="<audit XML; poll for all 10 sibling XMLs at <run_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml through <run_temp_dir>/pr-<N>/loop-<L>-k.outcomes.xml (60s timeout, 2s interval); on timeout: log diagnostics entry, proceed with validated findings from available XMLs; validate each finding: file exists, line in bounds, excerpt matches claimed line, category A-J, severity P0/P1/P2; quarantine hallucinated findings to <run_temp_dir>/pr-<N>/loop-<L>-diagnostics.json under validator_rejected; de-dup by (file, line, category), max severity wins, keep longest description on conflict; re-id as loop<L>-<K>; write <worktree_path>/.bugteam-pr<N>-loop<L>.outcomes.xml; post review>")
66
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-b", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant b", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml; skip PR posting>")
67
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-c", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant c", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-c.outcomes.xml; skip PR posting>")
68
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-d", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant d", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-d.outcomes.xml; skip PR posting>")
69
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-e", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant e", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-e.outcomes.xml; skip PR posting>")
70
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-f", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant f", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-f.outcomes.xml; skip PR posting>")
71
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-g", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant g", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-g.outcomes.xml; skip PR posting>")
72
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-h", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant h", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-h.outcomes.xml; skip PR posting>")
73
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-i", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant i", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-i.outcomes.xml; skip PR posting>")
74
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-j", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant j", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-j.outcomes.xml; skip PR posting>")
75
- Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-k", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant k", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-k.outcomes.xml; skip PR posting>")
144
+ Agent(
145
+ subagent_type="clean-coder",
146
+ name="bugfix-pr<N>-loop<L>",
147
+ model="opus",
148
+ mode="bypassPermissions",
149
+ run_in_background=true,
150
+ description="Bugfix PR <N> loop <L>",
151
+ prompt="<output of build_fix_prompt.py; see ../../_shared/pr-loop/scripts/build_fix_prompt.py>"
152
+ )
76
153
  ```
77
154
 
78
- Teammate `-a` is the opus validator: polls for all 10 sibling XMLs at explicit absolute paths under `<run_temp_dir>/pr-<N>` (60s timeout, 2s interval; on timeout: log diagnostics entry, proceed with validated findings from available XMLs), then validates each finding file exists, line in bounds, excerpt matches claimed line, category is A–J, severity is P0/P1/P2. Hallucinated findings are quarantined to `<run_temp_dir>/pr-<N>/loop-<L>-diagnostics.json` under `validator_rejected`. Valid findings are de-duplicated by `(file, line, category)` (max severity wins, keep longest description on conflict) and re-assigned merged IDs as `loop<L>-<K>`. The `-a` prompt must embed sibling paths as literal absolutes so `Read` works without discovery.
79
-
80
- All subagents self-terminate via background completion. The lead awaits only the validator (-a) notification (120s timeout). Missing notification → hard blocker.
81
-
82
- ## FIX action (fresh teammate)
83
-
84
- `Agent` shape in `SKILL.md`. The teammate sees only the latest audit’s findings — each `Agent` call starts with a fresh context window; prior-loop findings, fix history, and chat stay in the lead.
155
+ The teammate sees only the latest audit’s findings each `Agent` call starts with a fresh context window; prior-loop findings, fix history, and chat stay in the lead.
85
156
 
86
- Pass finding comment URL and id for each finding (from `loop_comment_index`) in the XML prompt so the teammate owns replies. After commit: one reply per finding (`Fixed in <commit_sha>` or `Could not address this loop: <one-line reason>`). Same identity model as bugfind: teammate posts; lead waits.
157
+ Pass finding comment URL, comment id, and thread node id for each finding (from `loop_comment_index`) in the XML prompt so the teammate owns both the reply and the thread resolution. After commit, the teammate posts one reply per finding using the unified template at [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md) — the full header / horizontal rule / `<action_heading> ✅` / explanation / anchored-bullet / closing-paragraph skeleton, with `<status_line>` set per the path (`Fixed in <short_sha>` for `status=fixed`, `Could not address this loop` for `status=could_not_address`, `Hook blocked the fix commit` for `status=hook_blocked`). Per-thread reply and `resolve_thread` are atomic — see [`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md) step 12 for the exact sequence. Same identity model as bugfind: teammate posts; lead waits.
87
158
 
88
159
  After replies, the teammate writes outcome XML (schema in [`../PROMPTS.md`](../PROMPTS.md)).
89
160
 
@@ -93,8 +164,10 @@ Same self-termination model as bugfind. Missing notification → hard blocker.
93
164
 
94
165
  `approve: false` → `error: bugfix teammate refused shutdown` → Step 4 then 5.
95
166
 
96
- Substitute placeholders from `last_findings` into the fix prompt per [`../PROMPTS.md`](../PROMPTS.md).
167
+ Substitute placeholders from `last_findings` into the fix prompt per [`../PROMPTS.md`](../PROMPTS.md). The spawn XML includes TaskCreate/self_audit_checklist for task tracking — the FIX subagent MUST create tasks before starting.
97
168
 
98
169
  **Verify push:** `git rev-parse HEAD` after fix must differ from before; new HEAD must exist on `origin/<branch>` (`git fetch origin <branch> && git rev-parse origin/<branch>` matches `HEAD`). If HEAD did not change → `stuck — bugfix teammate could not address findings`.
99
170
 
171
+ **Scope verification.** Run `git diff HEAD~1 --name-only` and compare against the set of files referenced in `bugs_to_fix`. When the commit touches files NOT in the `bugs_to_fix` list, judge whether the extras are a coherent part of the fix: a shared helper the auditor did not think to name, a test file that exercises the fix, a config update the fix requires. If the extras are coherent with the fix, note them in the outcome XML's `<scope_notes>` and keep the outcome as `fixed`. If the extras look unrelated, suspicious, or out of scope, downgrade to `unverified_fixed` with reason `commit touched unexpected files: <list>`. The auditor's file list is a default, not a contract — the fix's coherence is the contract.
172
+
100
173
  `last_action = "fixed"`. Append fix line to `audit_log`.
@@ -21,7 +21,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
21
21
  "id": "loop<L>-<K>",
22
22
  "file": "path/relative/to/repo/root.py",
23
23
  "line": 123,
24
- "category": "A | B | C | D | E | F | G | H | I | J",
24
+ "category": "A | B | C | D | E | F | G | H | I | J | K",
25
25
  "severity": "P0 | P1 | P2",
26
26
  "excerpt": "verbatim code snippet from the offending line(s)",
27
27
  "failure_mode": "one sentence describing what goes wrong and when",
@@ -37,7 +37,7 @@ Used when an audit investigates a category and does NOT find a bug. Bare "verifi
37
37
 
38
38
  ```json
39
39
  {
40
- "category": "A | B | C | D | E | F | G | H | I | J",
40
+ "category": "A | B | C | D | E | F | G | H | I | J | K",
41
41
  "files_opened": ["file1.py", "file2.py"],
42
42
  "lines_quoted": [
43
43
  {"file": "file1.py", "line": 88, "text": "verbatim line content"}
@@ -89,25 +89,7 @@ After the primary finding list is complete, every audit runs a second pass again
89
89
 
90
90
  The audit must either produce new Shape A findings citing new file:line references not present in the first pass, or cite explicit Shape B adversarial-probe entries for each category it re-examined. An adversarial pass that returns "nothing new, confident first pass was complete" is REJECTED — produce evidence or findings, not confidence.
91
91
 
92
- ## Haiku secondary auditor
93
-
94
- For single-subagent skills (`/qbug`, `/findbugs`) the LEAD spawns two `Agent()` calls in one message:
95
-
96
- - **Primary** — `subagent_type=clean-coder`, `model=sonnet` (for qbug cycle) or `subagent_type=code-quality-agent`, `model=sonnet` (for findbugs clean-room).
97
- - **Secondary (Haiku)** — `subagent_type=code-quality-agent`, `model=haiku`, same self-contained clean-room prompt shape used by `/findbugs`.
98
-
99
- Both audit the same diff. The secondary returns findings to the LEAD only — never posted to the PR.
100
-
101
- Merge rules:
102
-
103
- - **De-dup key**: `(file, line, category)`.
104
- - **Severity conflict**: max wins (P0 > P1 > P2).
105
- - **Unique-to-Haiku findings**: added to the primary set with Haiku's severity and source annotation.
106
- - **Unique-to-primary findings**: kept as-is.
107
- - **Zero Haiku findings**: primary set trusted; proceed.
108
- - **Malformed or non-parseable Haiku output**: lead trusts the primary set, logs the event in `loop-<L>-diagnostics.json` under `haiku_findings` as `[{"parse_error": "<message>"}]`.
109
-
110
- For multi-subagent skills (`/bugteam`) the parallel-auditors pattern in [`audit-and-teammates.md`](audit-and-teammates.md) already provides cross-model coverage via 10 haiku auditors + opus validator.
92
+ For `/bugteam`, the single audit agent provides per-category coverage by walking all A–K rubrics in one invocation.
111
93
 
112
94
  ## Post-fix self-audit
113
95
 
@@ -120,7 +102,7 @@ Sequence:
120
102
  3. Run `py_compile` (or language-equivalent) on each modified file.
121
103
  4. Compute `fix_diff` against pre-fix contents for the modified set.
122
104
  5. Run `bugteam_code_rules_gate.py` with explicit paths for every modified file.
123
- 6. Spawn a scoped audit of `fix_diff` with full A–J rigor, Shape A/B contract, adversarial pass, AND Haiku secondary in parallel (paranoid mode on post-fix).
105
+ 6. Spawn a scoped audit of `fix_diff` with full A–K rigor, Shape A/B contract, adversarial pass, AND Haiku secondary in parallel (paranoid mode on post-fix).
124
106
  7. Any new findings become same-loop fix-targets. Internal iteration count increments by one.
125
107
  8. After 3 internal iterations with fresh findings each time, exit `stuck: post-fix audit not converging`.
126
108
  9. Only when `gate_findings` empty AND `post_fix_findings` empty: `git add`, commit, push.
@@ -155,7 +155,7 @@ Each section names exactly one target file, the literal text or regex to add, an
155
155
  **Verification step (one line, no `$(...)`):**
156
156
 
157
157
  ```
158
- python C:/Users/jon/.claude/skills/bugteam/scripts/bugteam_code_rules_gate.py /tmp/pr70_writer.py /tmp/pr70_summary.py /tmp/pr73_constants.py /tmp/pr73_writer.py
158
+ python $HOME/.claude/skills/bugteam/scripts/bugteam_code_rules_gate.py /tmp/pr70_writer.py /tmp/pr70_summary.py /tmp/pr73_constants.py /tmp/pr73_writer.py
159
159
  ```
160
160
 
161
161
  Run after the K and L deterministic detectors land in §c/d below; the categories M and N stay rubric-only and are exercised by replaying PR #70 / PR #73 through `/bugteam` with the new PROMPTS.md and observing that the audit posts findings keyed to lines 158 (M), 125 (rubric N — naming clarity), 263 (rubric N — PR-description drift), 361 (initial/final standards review — file length), and 206 (N — wrapper plumb-through).
@@ -348,7 +348,7 @@ Wire into `run_gate` the same way as Detector 1, by appending its output to `iss
348
348
  **Verification step:**
349
349
 
350
350
  ```
351
- python C:/Users/jon/.claude/skills/bugteam/scripts/bugteam_code_rules_gate.py /tmp/pr70_writer.py /tmp/pr70_summary.py /tmp/pr73_constants.py /tmp/pr73_writer.py /tmp/pr73_tracker.py
351
+ python $HOME/.claude/skills/bugteam/scripts/bugteam_code_rules_gate.py /tmp/pr70_writer.py /tmp/pr70_summary.py /tmp/pr73_constants.py /tmp/pr73_writer.py /tmp/pr73_tracker.py
352
352
  ```
353
353
 
354
354
  Expected output after the patch lands: at minimum one `Column-name string magic 'theme_name' - extract to config` line on `pr70_writer.py` (Copilot id 3153098661) and one `Wrapper 'flush' drops optional kwargs ['loud_banner_stream'] of delegate 'flush'` line on `pr73_tracker.py` (Copilot id 3153475331).
@@ -488,13 +488,16 @@ def check_library_print(content: str, file_path: str) -> list[str]:
488
488
  all_issues.extend(check_library_print(content, file_path))
489
489
  ```
490
490
 
491
- **Verification step:**
491
+ **Verification step** — invoke the
492
+ [`probe_code_rules_enforcer_check.py`](../scripts/probe_code_rules_enforcer_check.py)
493
+ script (which dynamically loads `code_rules_enforcer` and runs the named
494
+ detector against a fixture):
492
495
 
493
496
  ```
494
- python -c "import importlib.util, sys; spec=importlib.util.spec_from_file_location('e','C:/Users/jon/.claude/hooks/blocking/code_rules_enforcer.py'); m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m); content=open('/tmp/pr73_constants.py').read(); print(m.check_collection_prefix(content,'shared_utils/theme_db/config/constants.py'))"
497
+ python "${CLAUDE_SKILL_DIR}/scripts/probe_code_rules_enforcer_check.py" check_collection_prefix /tmp/pr73_constants.py shared_utils/theme_db/config/constants.py
495
498
  ```
496
499
 
497
- Expected output after the patch lands: a list containing `Line 91: Collection constant THEMES_INSERT_REQUIRED_COLUMN_NAMES - prefix with ALL_ (CODE_RULES §5)`. The same command against `/tmp/pr73_writer.py` (Copilot id 3153475297) emits `Line 296: Collection parameter column_value_pairs - prefix with all_ (CODE_RULES §5)`. Replacing the call with `m.check_library_print` against `/tmp/pr70_summary.py` (Copilot id 3153098727) emits at minimum one `Line 256: Library print() - …` line.
500
+ Expected output after the patch lands: a list containing `Line 91: Collection constant THEMES_INSERT_REQUIRED_COLUMN_NAMES - prefix with ALL_ (CODE_RULES §5)`. The same command against `/tmp/pr73_writer.py` (Copilot id 3153475297) emits `Line 296: Collection parameter column_value_pairs - prefix with all_ (CODE_RULES §5)`. Re-running with `check_library_print /tmp/pr70_summary.py shared_utils/theme_db/summary.py` (Copilot id 3153098727) emits at minimum one `Line 256: Library print() - …` line.
498
501
 
499
502
  **Justification for touching `code_rules_enforcer.py`:** the root-cause statement names write-time enforcement as the right layer for collection-prefix and library-print, because both rules in `CODE_RULES.md §5` are mechanical (no judgment), produce concrete fixes, and were the dominant source of follow-up Copilot findings (3 of 8 inventory rows). The bugteam pre-flight gate alone is insufficient — it only fires before each AUDIT, so a clean-coder fix pass that introduces a new violation lives unblocked until the next gate run; write-time enforcement closes that window.
500
503
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Core principle (expanded)
4
4
 
5
- Background subagents (`Agent(..., run_in_background=true)`) run the audit-and-fix loop until convergence. The bugfind subagent audits clean-room (own context window, no chat history); the bugfix subagent addresses each audits findings; both spawn fresh per loop with no shared state. A 10-loop hard cap prevents runaway cost. Project permissions are granted at session start and revoked at session end.
5
+ One audit agent (`code-quality-agent`, opus) walks all A–K categories per loop. One fix agent (`clean-coder`, opus) addresses the audit's findings.
6
6
 
7
7
  Fresh-spawn clean-room isolation: each `Agent` call creates a new subagent with its own context window and no access to prior conversation. After the subagent writes its outcome XML and self-terminates, the lead reads the file. Results never accumulate in the lead’s context beyond the XML artifact. Verbatim Anthropic quotes and URLs: [`../sources.md`](../sources.md).
8
8
 
@@ -12,7 +12,7 @@ The top-of-file list exists so partial reads (for example `head -100`) still sho
12
12
 
13
13
  ## When `/bugteam` applies (narrative)
14
14
 
15
- The user wants automated convergence on a clean PR without babysitting each step. Typed `/bugteam` once means full authorization for up to ten audit cycles and the corresponding fix commits.
15
+ The user wants automated convergence on a clean PR without babysitting each step. Typed `/bugteam` once means full authorization for up to twenty audit cycles and the corresponding fix commits.
16
16
 
17
17
  ### Refusal reasons (detail)
18
18
 
@@ -1,86 +1,79 @@
1
- # GitHub PR comments (Step 2.5)
1
+ # GitHub PR comments
2
2
 
3
- Per-loop pull-request reviews: findings render as a tree under one parent review (similar to Cursor Bugbot). **Teammates own all PR comment posting** — bugfind posts the review (parent body plus child finding comments in one batched POST); bugfix posts fix replies. Comment, review, and reply POSTs belong to teammates. The lead’s single PR write is the final description rewrite at Step 4.5 (`pr-description-writer`).
3
+ Per-loop pull-request reviews and post-fix replies use two distinct transports:
4
4
 
5
- - **Per-loop review** — One `POST /pulls/<number>/reviews` per loop, posted by the bugfind teammate **after** auditing. The review body is the loop header (audit counts); the review’s `comments[]` array holds one anchored finding per P0/P1/P2 finding. GitHub renders a single collapsible thread with each finding as a child comment.
5
+ - **Per-loop audit review** — posted via [`post_audit_thread.py`](../../../_shared/pr-loop/scripts/post_audit_thread.py). One review per audit pass. `APPROVE` on CLEAN (the request event; GitHub stores it as `state=APPROVED`; body documents "no findings", zero inline comments). `REQUEST_CHANGES` on DIRTY (one inline anchored comment per finding; each becomes its own resolvable thread).
6
+ - **Fix replies** — posted via the GitHub MCP `add_reply_to_pull_request_comment` after the fix commit lands. The reply body uses the unified template at [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md); reply and `resolve_thread` are atomic per thread.
6
7
 
7
- - **Fix replies** — Reply to each child finding comment after the commit lands. Body: `Fixed in <commit_sha>` if addressed, or `Could not address this loop: <one-line reason>` if not. The `/pulls/<number>/comments/<id>/replies` endpoint works on any review comment, including those created as part of a review.
8
+ ## Per-loop audit review (post_audit_thread.py)
8
9
 
9
- **Ordering:** Bugfind audits first, buffers findings, validates anchors against the captured diff, then posts the review **once** at the end. The review body states the finding count authoritatively. Keep all posting in that single end-of-loop review POST.
10
+ Run the script at the end of every audit pass:
10
11
 
11
- ## MCP tool shapes (teammate)
12
+ ```
13
+ python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/post_audit_thread.py" \
14
+ --skill bugteam \
15
+ --owner <owner> \
16
+ --repo <repo> \
17
+ --pr-number <N> \
18
+ --commit <head_sha> \
19
+ --state <CLEAN|DIRTY> \
20
+ --findings-json <path>
21
+ ```
12
22
 
13
- All three POSTs use MCP tool calls. Body text with markdown (backticks, newlines, quotes) passes through safely as string parameters no temp files, no jq, no shell pipes.
23
+ Capture `<head_sha>` via `git rev-parse HEAD` in the subagent cwd immediately before this call so the review attaches to the commit the audit actually scoped.
14
24
 
15
- ### Per-loop review (one POST creates parent + children)
25
+ `--findings-json` points to a JSON file whose root is a list of objects shaped `{path, line, side, severity, description, fix_summary}`. Build it from the merged Shape A findings: finding `file` → `path`. Each finding's `failure_mode` carries the full audit-to-fix handoff text per [`agents/code-quality-agent.md`](../../../agents/code-quality-agent.md); split `failure_mode` at the literal `Fix:` heading so the failure narrative becomes `description` and the suffix beginning at `Fix:` (including the trailing `Validation:` clause) becomes `fix_summary`. When a finding's `failure_mode` omits the `Fix:` heading, write the full text to BOTH `description` and `fix_summary` so the script's body template (`INLINE_COMMENT_BODY_TEMPLATE` in [`scripts/config/post_audit_thread_constants.py`](../../../_shared/pr-loop/scripts/config/post_audit_thread_constants.py)) renders coherently. Set `side="RIGHT"` for every entry. On CLEAN the list is empty (`[]`); on DIRTY the list carries one entry per finding.
16
26
 
17
- Build `comments[]` programmatically from buffered, diff-anchored findings. Single-line shape: `{path, line, side: "RIGHT", body: <finding markdown>}`. Multi-line: `{path, start_line, start_side: "RIGHT", line, side: "RIGHT", body: ...}` (all four anchor fields required).
27
+ The script handles retries internally 1s / 4s / 16s backoff across four attempts (one initial plus three retries). Exit codes:
18
28
 
19
- ```
20
- pull_request_review_write(
21
- method="create",
22
- event="COMMENT",
23
- body=<review_body_markdown>,
24
- commitID=<head_sha_at_post_time>,
25
- owner=<owner>, repo=<repo>, pullNumber=<pull_number>,
26
- comments=[
27
- {path: <file_1>, line: <line_1>, side: "RIGHT", body: <finding_1_markdown>}
28
- [, ... one object per anchored finding ...]
29
- ]
30
- )
31
- ```
29
+ - `0` — review posted; the new review's `html_url` is on stdout.
30
+ - `1` — user input error (bad arguments, malformed findings JSON, missing template).
31
+ - `2` — retry exhaustion. Hard blocker; the lead exits `error: post_audit_thread retry exhausted` without retrying and without falling back to a flat issue comment.
32
32
 
33
- Response includes the parent review `html_url` and a `comments` array of child comments (`id`, `html_url`). Harvest children in index order and align with the finding list.
33
+ Harvest the parent review URL from stdout, then extract the numeric review id from the URL's `#pullrequestreview-<id>` suffix (the trailing URL fragment of `html_url`, the part after `#`). Fetch child-comment URLs via `pull_request_read(method="get_review_comments", owner=<owner>, repo=<repo>, pullNumber=<N>)` filtered to that review id. That same response carries each comment's PR review thread node id (e.g. `PRRT_kwDOxxx`) — capture it alongside the numeric comment id. Match children to findings in the order they appear in the findings JSON, and store the mapping as `loop_comment_index[finding_id]` carrying both `finding_comment_id` (numeric) and `thread_node_id` (`PRRT_kwDOxxx`) for the FIX step to reply against and resolve.
34
34
 
35
- ### Fix reply
35
+ The script reads its body skeleton from [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md) at runtime, so the template doc remains the single source of truth for the body shape — edits there propagate without restarting the caller.
36
36
 
37
- ```
38
- add_reply_to_pull_request_comment(
39
- commentId=<finding_comment_id>,
40
- body=<reply_markdown>,
41
- owner=<owner>, repo=<repo>, pullNumber=<pull_number>
42
- )
43
- ```
44
-
45
- ### Review POST failure fallback
37
+ ## Fix reply (MCP)
46
38
 
47
- Top-level PR comment via issue-comments (`issue_number` is the PR number):
39
+ After the fix commit lands, post one reply per finding thread and resolve the thread atomically.
48
40
 
49
41
  ```
50
- add_issue_comment(
51
- owner=<owner>, repo=<repo>,
52
- issueNumber=<pull_number>,
53
- body=<full_fallback_markdown>
42
+ mcp__plugin_github_github__add_reply_to_pull_request_comment(
43
+ owner="<owner>",
44
+ repo="<repo>",
45
+ pullNumber=<number>,
46
+ commentId=<finding_comment_id>,
47
+ body="<reply body using unified template>"
54
48
  )
55
49
  ```
56
50
 
57
- `<head_sha_at_post_time>` is the SHA at post time (`git rev-parse HEAD` in the teammate’s working directory immediately before the POST). The review anchors finding comments to the head SHA at audit time (before this loop’s fix lands).
58
-
59
- Body text is passed directly as string parameters to the MCP tool calls — no temp files, no jq, no shell pipes.
51
+ The reply body uses the unified template from [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md). Per-status `<status_line>` / `<action_heading>` values live in [`../PROMPTS.md`](../PROMPTS.md) § FIX execution step 8.
60
52
 
61
- ## Review body template (`<tmp_review_body.md>`)
53
+ Immediately after the reply call returns, resolve the same thread:
62
54
 
63
55
  ```
64
- ## /bugteam loop <N> audit: <P0>P0 / <P1>P1 / <P2>P2
65
-
66
- <if any findings could not be anchored to a diff line, include this section:>
67
- ### Findings without a diff anchor
68
-
69
- - **[severity] title** — <file>:<line> — <one-line description>
56
+ mcp__plugin_github_github__pull_request_review_write(
57
+ method="resolve_thread",
58
+ owner="<owner>",
59
+ repo="<repo>",
60
+ pullNumber=<number>,
61
+ threadId=<thread_node_id>
62
+ )
70
63
  ```
71
64
 
72
- If the audit returns zero findings, still post **one** review with `event=COMMENT`, empty `comments[]`, and body `## /bugteam loop <N> audit: 0P0 / 0P1 / 0P2 clean` so each loop’s section is self-contained on the PR.
65
+ `<thread_node_id>` is the PR review thread node ID (`PRRT_kwDOxxx`) harvested above when calling `get_review_comments`, distinct from the numeric comment ID used in the reply call. See [obstacles/fix-resolve-thread.md](obstacles/fix-resolve-thread.md) for the full identifier-shape rationale.
73
66
 
74
- ## Anchor-validation fallback (teammate)
67
+ The two calls form one atomic per-thread action. Do not yield to the lead between them. Do not batch all replies before any resolves.
75
68
 
76
- GitHub rejects the entire review POST if any `comments[]` entry targets a line not in the diff. Before posting, validate every finding’s `(file, line)` against the captured diff. Findings not in the diff are **not** added to `comments[]`; list them in the review body under `### Findings without a diff anchor`. Outcome XML: `used_fallback="true"`, `finding_comment_id=""`, `finding_comment_url=<review_url>` (parent URL when there is no child). Log fallback count in outcome XML for the lead’s final report. The loop continues; anchor mismatch does not abort.
69
+ ## Anchor validation
77
70
 
78
- ## Review POST failure fallback
71
+ GitHub's reviews endpoint rejects the entire POST if any inline comment in `comments[]` targets a line not present in the diff at `--commit`. Validate `(path, line)` against the captured diff before adding a finding to the findings JSON. Findings without a diff anchor stay out of the JSON; surface them in the calling skill's user-facing output instead so the audit pass still completes.
79
72
 
80
- If the review POST fails (rate limit, network, malformed payload), fall back to one top-level issue comment containing the review body plus every finding inline (severity, file:line, description). Every finding in that run: `used_fallback="true"`, `finding_comment_url` = issue-comment URL. Use `add_issue_comment` (see MCP tool reference below).
73
+ ## GitHub MCP tools used
81
74
 
82
- ## MCP tool reference
75
+ - `add_reply_to_pull_request_comment` fix replies on existing review comments.
76
+ - `pull_request_review_write` (`method="resolve_thread"`) — thread resolution after the reply lands; called atomically with the reply.
77
+ - `pull_request_read` (`method="get_review_comments"`) — harvest child-comment ids/urls after the script's parent review posts.
83
78
 
84
- - Per-loop batched review: `pull_request_review_write(method="create", event="COMMENT", body=..., commitID=..., owner=..., repo=..., pullNumber=..., comments=[...])` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews`
85
- - Fix reply: `add_reply_to_pull_request_comment(commentId=..., body=..., owner=..., repo=..., pullNumber=...)` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies`
86
- - Review-POST failure fallback: `add_issue_comment(owner=..., repo=..., issueNumber=..., body=...)` — wraps `POST /repos/{owner}/{repo}/issues/{issue_number}/comments`
79
+ Reference: https://github.com/github/github-mcp-server.
@@ -0,0 +1,13 @@
1
+ # Assign IDs
2
+
3
+ Assign each finding a stable finding_id (loop<L>-<K>), 1-based within loop
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Capture excerpts
2
+
3
+ Capture verbatim excerpts, validate anchors against diff, split into anchored and unanchored buckets
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Walk categories
2
+
3
+ Audit every category A through K. Each returns Shape A finding or Shape B verified-clean. No skipped categories.
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn `Agent(run_in_background=true)` — brief it: check `jl-cmd/claude-code-config` for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Write outcome XML
2
+
3
+ Write outcome XML to worktree path with finding IDs, thread node IDs, and review URL
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Append summary URL
2
+
3
+ Append fix summary URL to parent review via add_reply_to_pull_request_comment
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Apply fixes
2
+
3
+ Apply each addressable fix, skip only with explicit reason
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Git add + commit
2
+
3
+ git add by explicit path, commit with summary, capture hook failures
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Git push
2
+
3
+ Fast-forward push, no flag overrides
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Post fix replies
2
+
3
+ Post fix reply on each finding comment thread via add_reply_to_pull_request_comment
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+
@@ -0,0 +1,13 @@
1
+ # Publish fix summary
2
+
3
+ Publish fix summary HTML via /doc-gist with commit SHA, files, per-fix descriptions
4
+
5
+ ## Self-population
6
+
7
+ Hit a wall on this step? Spawn a background agent to record it. Keep working.
8
+
9
+ 1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
10
+ 2. Tell the agent your obstacle and what fixed it. It writes the entry below.
11
+
12
+ ## Obstacles
13
+