claude-dev-env 1.83.0 → 1.85.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 (186) 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/pr_loop_shared_constants/CLAUDE.md +1 -1
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +8 -0
  6. package/_shared/pr-loop/scripts/reviews_disabled.py +2 -0
  7. package/_shared/pr-loop/scripts/terminology_sweep.py +85 -39
  8. package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +212 -0
  9. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +18 -0
  10. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +18 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +37 -0
  12. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +14 -0
  13. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +94 -4
  14. package/agents/clean-coder.md +3 -0
  15. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
  16. package/bin/install.mjs +16 -8
  17. package/bin/install.test.mjs +17 -6
  18. package/commands/CLAUDE.md +0 -1
  19. package/docs/CODE_RULES.md +1 -1
  20. package/hooks/blocking/CLAUDE.md +0 -4
  21. package/hooks/blocking/claude_md_orphan_file_blocker.py +1 -1
  22. package/hooks/blocking/code_rules_constants_config.py +5 -0
  23. package/hooks/blocking/code_rules_docstrings.py +133 -19
  24. package/hooks/blocking/code_rules_enforcer.py +4 -0
  25. package/hooks/blocking/code_rules_imports_logging.py +10 -6
  26. package/hooks/blocking/code_rules_magic_values.py +5 -0
  27. package/hooks/blocking/code_rules_naming_collection.py +15 -8
  28. package/hooks/blocking/code_rules_paired_test.py +3 -2
  29. package/hooks/blocking/code_rules_shared.py +34 -0
  30. package/hooks/blocking/code_rules_string_magic.py +1 -1
  31. package/hooks/blocking/code_rules_unused_imports.py +2 -2
  32. package/hooks/blocking/duplicate_rmtree_helper_blocker.py +4 -4
  33. package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +29 -0
  34. package/hooks/blocking/test_code_rules_enforcer_docstring_prose_wall_illustration.py +197 -0
  35. package/hooks/blocking/test_code_rules_enforcer_docstring_runon_sentence.py +27 -0
  36. package/hooks/blocking/test_code_rules_enforcer_naive_datetime.py +24 -0
  37. package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +33 -0
  38. package/hooks/blocking/test_code_rules_enforcer_split_shared.py +23 -0
  39. package/hooks/blocking/test_code_rules_magic_values.py +54 -0
  40. package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +0 -6
  41. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +184 -0
  42. package/hooks/blocking/test_shared_stdin_adoption.py +5 -30
  43. package/hooks/hooks_constants/CLAUDE.md +0 -3
  44. package/hooks/hooks_constants/blocking_check_limits.py +4 -0
  45. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  46. package/hooks/hooks_constants/duplicate_rmtree_helper_blocker_constants.py +0 -1
  47. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -5
  48. package/hooks/validation/post_tool_use_dispatcher.py +1 -1
  49. package/hooks/validation/test_post_tool_use_dispatcher.py +51 -35
  50. package/hooks/workflow/CLAUDE.md +2 -8
  51. package/package.json +1 -1
  52. package/rules/CLAUDE.md +1 -1
  53. package/rules/docstring-prose-matches-implementation.md +1 -1
  54. package/rules/env-var-table-code-drift.md +1 -1
  55. package/rules/package-inventory-stale-entry.md +1 -1
  56. package/rules/paired-test-coverage.md +1 -1
  57. package/rules/plain-illustrative-docstrings.md +35 -1
  58. package/skills/CLAUDE.md +6 -1
  59. package/skills/_shared/pr-loop/CLAUDE.md +1 -0
  60. package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -0
  61. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
  62. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +45 -0
  63. package/skills/_shared/pr-loop/scripts/test_write_handoff.py +201 -0
  64. package/skills/_shared/pr-loop/scripts/write_handoff.py +309 -0
  65. package/skills/autoconverge/SKILL.md +82 -58
  66. package/skills/autoconverge/reference/closing-report.md +6 -6
  67. package/skills/autoconverge/reference/convergence.md +17 -15
  68. package/skills/autoconverge/reference/gotchas.md +6 -3
  69. package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +2 -9
  70. package/skills/autoconverge/workflow/converge.contract.test.mjs +87 -13
  71. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +1 -1
  72. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +16 -9
  73. package/skills/autoconverge/workflow/converge.mjs +71 -74
  74. package/skills/autoconverge/workflow/render_report.py +7 -11
  75. package/skills/bugteam/CLAUDE.md +1 -1
  76. package/skills/bugteam/PROMPTS.md +7 -6
  77. package/skills/bugteam/SKILL.md +25 -72
  78. package/skills/bugteam/reference/CLAUDE.md +1 -3
  79. package/skills/bugteam/reference/README.md +1 -1
  80. package/skills/bugteam/reference/audit-and-teammates.md +1 -1
  81. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +1 -1
  82. package/skills/bugteam/reference/team-setup.md +8 -7
  83. package/skills/bugteam/scripts/CLAUDE.md +0 -6
  84. package/skills/bugteam/scripts/README.md +0 -4
  85. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +0 -1
  86. package/skills/code/SKILL.md +2 -0
  87. package/skills/copilot-review/CLAUDE.md +1 -1
  88. package/skills/copilot-review/SKILL.md +25 -23
  89. package/skills/findbugs/CLAUDE.md +2 -2
  90. package/skills/findbugs/SKILL.md +22 -83
  91. package/skills/fixbugs/SKILL.md +2 -4
  92. package/skills/log-audit/CLAUDE.md +20 -0
  93. package/skills/log-audit/SKILL.md +68 -0
  94. package/skills/log-audit/reference/CLAUDE.md +9 -0
  95. package/skills/log-audit/reference/charter.md +52 -0
  96. package/skills/log-audit/scripts/CLAUDE.md +27 -0
  97. package/skills/log-audit/scripts/cluster_recurrences.py +261 -0
  98. package/skills/log-audit/scripts/collect_log_window.py +199 -0
  99. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +12 -0
  100. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +23 -0
  101. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +24 -0
  102. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +49 -0
  103. package/skills/log-audit/scripts/mine_copilot_findings.py +302 -0
  104. package/skills/log-audit/scripts/test_cluster_recurrences.py +160 -0
  105. package/skills/log-audit/scripts/test_collect_log_window.py +111 -0
  106. package/skills/log-audit/scripts/test_mine_copilot_findings.py +126 -0
  107. package/skills/monitor-open-prs/SKILL.md +2 -2
  108. package/skills/post-audit-findings/SKILL.md +84 -0
  109. package/skills/pr-converge/CLAUDE.md +2 -0
  110. package/skills/pr-converge/SKILL.md +99 -60
  111. package/skills/pr-converge/reference/CLAUDE.md +1 -1
  112. package/skills/pr-converge/reference/convergence-gates.md +16 -19
  113. package/skills/pr-converge/reference/examples.md +5 -5
  114. package/skills/pr-converge/reference/fix-protocol.md +16 -43
  115. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +1 -1
  116. package/skills/pr-converge/reference/per-tick.md +24 -45
  117. package/skills/pr-converge/reference/state-schema.md +27 -0
  118. package/skills/pr-converge/scripts/README.md +3 -5
  119. package/skills/pr-fix-protocol/SKILL.md +70 -0
  120. package/skills/pr-loop-lifecycle/SKILL.md +73 -0
  121. package/skills/{bugteam → pr-loop-lifecycle}/reference/teardown-publish-permissions.md +22 -24
  122. package/skills/pr-scope-resolve/SKILL.md +48 -0
  123. package/skills/qbug/CLAUDE.md +4 -4
  124. package/skills/qbug/SKILL.md +46 -144
  125. package/skills/qbug/test_qbug_skill_audit_schema.py +2 -2
  126. package/skills/qbug/test_qbug_skill_post_fix_audit.py +1 -1
  127. package/skills/reviewer-gates/SKILL.md +96 -0
  128. package/skills/session-log/CLAUDE.md +7 -7
  129. package/skills/session-log/SKILL.md +27 -44
  130. package/skills/test_markdown_link_integrity.py +103 -0
  131. package/commands/doc-gist.md +0 -16
  132. package/hooks/blocking/_md_to_html_blocker_test_support.py +0 -65
  133. package/hooks/blocking/conftest.py +0 -30
  134. package/hooks/blocking/md_path_exemptions.py +0 -224
  135. package/hooks/blocking/md_to_html_blocker.py +0 -155
  136. package/hooks/blocking/test_md_to_html_blocker_exemptions.py +0 -434
  137. package/hooks/blocking/test_md_to_html_blocker_extensions.py +0 -157
  138. package/hooks/blocking/test_md_to_html_blocker_path_resolution.py +0 -336
  139. package/hooks/hooks_constants/doc_gist_auto_publish_constants.py +0 -18
  140. package/hooks/hooks_constants/html_companion_constants.py +0 -20
  141. package/hooks/hooks_constants/md_to_html_blocker_constants.py +0 -76
  142. package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +0 -125
  143. package/hooks/workflow/doc_gist_auto_publish.py +0 -144
  144. package/hooks/workflow/md_to_html_companion.py +0 -358
  145. package/hooks/workflow/test_doc_gist_auto_publish.py +0 -117
  146. package/hooks/workflow/test_md_to_html_companion.py +0 -613
  147. package/skills/bugteam/reference/audit-contract.md +0 -163
  148. package/skills/bugteam/scripts/_bugteam_permissions_common.py +0 -455
  149. package/skills/bugteam/scripts/bugteam_scripts_constants/claude_permissions_common_constants.py +0 -69
  150. package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -280
  151. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -266
  152. package/skills/bugteam/scripts/test__bugteam_permissions_common.py +0 -160
  153. package/skills/bugteam/scripts/test_agent_config_carveout.py +0 -356
  154. package/skills/bugteam/scripts/test_bugteam_permissions_common.py +0 -140
  155. package/skills/doc-gist/CLAUDE.md +0 -25
  156. package/skills/doc-gist/SKILL.md +0 -97
  157. package/skills/doc-gist/references/CLAUDE.md +0 -9
  158. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +0 -453
  159. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +0 -515
  160. package/skills/doc-gist/references/examples/03-code-review-pr.html +0 -638
  161. package/skills/doc-gist/references/examples/04-code-understanding.html +0 -491
  162. package/skills/doc-gist/references/examples/05-design-system.html +0 -629
  163. package/skills/doc-gist/references/examples/06-component-variants.html +0 -605
  164. package/skills/doc-gist/references/examples/07-prototype-animation.html +0 -455
  165. package/skills/doc-gist/references/examples/08-prototype-interaction.html +0 -396
  166. package/skills/doc-gist/references/examples/09-slide-deck.html +0 -592
  167. package/skills/doc-gist/references/examples/10-svg-illustrations.html +0 -492
  168. package/skills/doc-gist/references/examples/11-status-report.html +0 -528
  169. package/skills/doc-gist/references/examples/12-incident-report.html +0 -596
  170. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +0 -395
  171. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +0 -381
  172. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +0 -368
  173. package/skills/doc-gist/references/examples/16-implementation-plan.html +0 -702
  174. package/skills/doc-gist/references/examples/17-pr-writeup.html +0 -595
  175. package/skills/doc-gist/references/examples/18-editor-triage-board.html +0 -573
  176. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +0 -663
  177. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +0 -722
  178. package/skills/doc-gist/references/examples/21-decision-signoff.html +0 -546
  179. package/skills/doc-gist/references/examples/CLAUDE.md +0 -25
  180. package/skills/doc-gist/references/examples/README.md +0 -5
  181. package/skills/doc-gist/scripts/CLAUDE.md +0 -27
  182. package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +0 -10
  183. package/skills/doc-gist/scripts/doc_gist_scripts_constants/gist_upload_constants.py +0 -16
  184. package/skills/doc-gist/scripts/gist_upload.py +0 -177
  185. package/skills/doc-gist/scripts/test_gist_upload.py +0 -51
  186. /package/skills/{doc-gist/scripts/doc_gist_scripts_constants → log-audit/scripts/log_audit_constants}/__init__.py +0 -0
@@ -26,7 +26,7 @@ const CONFIG = {
26
26
  copilotMaxPolls: 8,
27
27
  sharedScripts: '$HOME/.claude/skills/pr-converge/scripts',
28
28
  prLoopScripts: '$HOME/.claude/_shared/pr-loop/scripts',
29
- bugteamRubric: '$HOME/.claude/skills/bugteam/reference/audit-contract.md',
29
+ bugteamRubric: '$HOME/.claude/_shared/pr-loop/audit-contract.md',
30
30
  }
31
31
 
32
32
  const REVIEWER_GATE_SENTINEL = 'CLAUDE_REVIEWER_GATE=autoconverge '
@@ -79,38 +79,32 @@ const convergeAgent = (prompt, options) =>
79
79
  agent(`${HEADLESS_SAFETY_PREAMBLE}${worktreeDirective(activeRepoPath)}${prompt}`, options)
80
80
 
81
81
  /**
82
- * Spawn a fresh git-utility Explore agent for a specific task. 'resolve-head'
83
- * prints the PR HEAD SHA, 'prefetch-main' fetches origin main so the review
84
- * lenses diff against an up-to-date base, and any other task reports whether the
85
- * branch has merge conflicts. The agent never edits code.
86
- * @param {string} task the short task name
87
- * @param {string} head optional HEAD SHA for conflict checks
88
- * @returns {Promise<object|string>} the structured output, or the transcript string when the 'prefetch-main' resume runs schema-less
82
+ * Spawn a fresh git-utility Explore agent for a specific task. The one task,
83
+ * 'preflight-git', bundles the three mechanical git reads into a single agent
84
+ * startup: it prints the PR HEAD SHA, fetches origin main so the review lenses
85
+ * diff against an up-to-date base, and polls GitHub mergeability, returning
86
+ * {sha, conflicting, fetched} in one structured result. The agent never edits
87
+ * code, so it runs on the cheapest model at low effort.
88
+ * @param {string} task the short task name ('preflight-git')
89
+ * @returns {Promise<object>} the structured PREFLIGHT_GIT_SCHEMA output
89
90
  */
90
- function runGitTask(task, head) {
91
- if (task === 'resolve-head') {
92
- return convergeAgent(
93
- `Print the current HEAD SHA of ${prCoordinates}. Run exactly:\n` +
94
- `gh api repos/${input.owner}/${input.repo}/pulls/${input.prNumber} --jq .head.sha\n` +
95
- `Return the full 40-character SHA in the sha field. Do not modify any files.`,
96
- { label: 'git-utility', phase: 'Converge', schema: HEAD_SCHEMA, agentType: 'Explore' },
97
- )
98
- }
99
- if (task === 'prefetch-main') {
100
- return convergeAgent(
101
- `Refresh the base ref for ${prCoordinates} so the parallel review lenses can diff against an up-to-date origin/main without each running its own fetch. Run exactly:\n` +
102
- `git fetch origin main\n` +
103
- `Do not edit, commit, push, rebase, or modify any files — fetch only.`,
104
- { label: 'git-utility', phase: 'Converge', agentType: 'Explore' },
105
- )
91
+ function runGitTask(task) {
92
+ if (task !== 'preflight-git') {
93
+ throw new Error(`runGitTask has no handler for task ${task}`)
106
94
  }
107
95
  return convergeAgent(
108
- `Report whether ${prCoordinates} (HEAD ${head}) has merge conflicts with its base branch. Do not edit, commit, push, or rebase — read only.\n\n` +
109
- `GitHub computes mergeability asynchronously, so .mergeable is null right after a push until it finishes. Poll until it resolves: run\n` +
96
+ `Run three read-only git preflight steps for ${prCoordinates}. Do not edit, commit, push, rebase, or modify any files — read only.\n\n` +
97
+ `STEP 1 resolve HEAD. Print the current PR HEAD SHA. Run exactly:\n` +
98
+ ` gh api repos/${input.owner}/${input.repo}/pulls/${input.prNumber} --jq .head.sha\n` +
99
+ `Return the full 40-character SHA in the sha field.\n\n` +
100
+ `STEP 2 — refresh the base ref so the parallel review lenses can diff against an up-to-date origin/main without each running its own fetch. Run exactly:\n` +
101
+ ` git fetch origin main\n` +
102
+ `Return fetched:true when the fetch completed, fetched:false when it failed.\n\n` +
103
+ `STEP 3 — report whether the PR has merge conflicts with its base branch. GitHub computes mergeability asynchronously, so .mergeable is null right after a push until it finishes. Poll until it resolves: run\n` +
110
104
  ` gh api repos/${input.owner}/${input.repo}/pulls/${input.prNumber} --jq '{mergeable: .mergeable, state: .mergeable_state}'\n` +
111
- `up to 5 times, 5 seconds apart (wait each 5-second interval inside this turn with the Monitor tool, per the WAITS AND POLLS rule above), stopping as soon as mergeable is true or false.\n\n` +
105
+ `up to 5 times, 5 seconds apart (wait each 5-second interval inside this turn with the Monitor tool, per the WAITS AND POLLS rule above), stopping as soon as mergeable is true or false.\n` +
112
106
  `Return conflicting:true when mergeable is false or state is "dirty" (the branch conflicts with the base). Return conflicting:false when mergeable is true, or when mergeable stays null after the full poll budget — mergeability is unknown, so let the bug checks proceed rather than rebase on a guess.`,
113
- { label: 'git-utility', phase: 'Converge', schema: MERGE_CONFLICT_SCHEMA, agentType: 'Explore' },
107
+ { label: 'git-utility', phase: 'Converge', schema: PREFLIGHT_GIT_SCHEMA, agentType: 'Explore', model: 'haiku', effort: 'low' },
114
108
  )
115
109
  }
116
110
 
@@ -558,11 +552,18 @@ const REVIEWER_AVAILABILITY_SCHEMA = {
558
552
  required: ['copilot', 'bugbot'],
559
553
  }
560
554
 
561
- const HEAD_SCHEMA = {
555
+ const PREFLIGHT_GIT_SCHEMA = {
562
556
  type: 'object',
563
557
  additionalProperties: false,
564
- properties: { sha: { type: 'string' } },
565
- required: ['sha'],
558
+ properties: {
559
+ sha: { type: 'string', description: 'the full 40-character PR HEAD SHA' },
560
+ conflicting: {
561
+ type: 'boolean',
562
+ description: 'true only when GitHub reports the PR branch conflicts with its base (mergeable:false or mergeable_state:dirty); false when it merges cleanly or mergeability could not be computed',
563
+ },
564
+ fetched: { type: 'boolean', description: 'true when git fetch origin main completed successfully' },
565
+ },
566
+ required: ['sha', 'conflicting', 'fetched'],
566
567
  }
567
568
 
568
569
  const FIX_SCHEMA = {
@@ -602,18 +603,6 @@ const REPAIR_EDIT_SCHEMA = {
602
603
  required: ['edited', 'rebased', 'resolvedWithoutCommit', 'summary'],
603
604
  }
604
605
 
605
- const MERGE_CONFLICT_SCHEMA = {
606
- type: 'object',
607
- additionalProperties: false,
608
- properties: {
609
- conflicting: {
610
- type: 'boolean',
611
- description: 'true only when GitHub reports the PR branch conflicts with its base (mergeable:false or mergeable_state:dirty); false when it merges cleanly or mergeability could not be computed',
612
- },
613
- },
614
- required: ['conflicting'],
615
- }
616
-
617
606
  const CONFLICT_EDIT_SCHEMA = {
618
607
  type: 'object',
619
608
  additionalProperties: false,
@@ -1003,10 +992,10 @@ function commitNeedsCodeRecovery(commitResult) {
1003
992
 
1004
993
  /**
1005
994
  * Decide whether a resolved HEAD SHA is safe to spawn lenses against. A dead
1006
- * resolve-head agent or a malformed result yields a falsy SHA; spawning lenses
995
+ * preflight-git agent or a malformed result yields a falsy SHA; spawning lenses
1007
996
  * against it interpolates the literal string 'HEAD undefined' into their prompts
1008
997
  * and produces a spurious clean verdict on a non-existent commit.
1009
- * @param {string|null|undefined} resolvedHead the SHA from the git-utility 'resolve-head' task
998
+ * @param {string|null|undefined} resolvedHead the SHA from the git-utility 'preflight-git' task
1010
999
  * @returns {boolean} true only when the SHA is a non-empty string
1011
1000
  */
1012
1001
  function isResolvedHeadUsable(resolvedHead) {
@@ -1014,12 +1003,12 @@ function isResolvedHeadUsable(resolvedHead) {
1014
1003
  }
1015
1004
 
1016
1005
  /**
1017
- * Decide whether the pre-flight merge-conflict check found the PR branch in
1018
- * conflict with its base. A dead check agent (null/undefined result) reports
1006
+ * Decide whether the pre-flight mergeability probe found the PR branch in
1007
+ * conflict with its base. A dead preflight agent (null/undefined result) reports
1019
1008
  * not-conflicting so the run proceeds straight to the bug checks rather than
1020
- * force-pushing a rebase on a verdict that does not exist — a transient check
1009
+ * force-pushing a rebase on a verdict that does not exist — a transient probe
1021
1010
  * failure must never trigger a destructive rebase.
1022
- * @param {object|null|undefined} mergeState the git-utility 'check-merge-conflicts' task result
1011
+ * @param {object|null|undefined} mergeState the git-utility 'preflight-git' task result carrying the conflicting field
1023
1012
  * @returns {boolean} true only when the check reported conflicting:true
1024
1013
  */
1025
1014
  function isMergeConflicting(mergeState) {
@@ -1370,7 +1359,7 @@ function runCopilotGate(head) {
1370
1359
  `Copilot can run out of usage. When the newest Copilot review on HEAD carries an out-of-usage notice — a body stating Copilot was unable to review because the user who requested the review has reached their quota limit, or any equivalent quota / premium-request / usage-limit exhaustion message rather than an actual code review — Copilot is down for this run: return {sha:${'`'}${head}${'`'}, clean:true, down:true, findings:[]} and stop. Do NOT re-request a review, do NOT keep polling, and do NOT treat the notice as a finding.\n\n` +
1371
1360
  `1. Read any existing Copilot review on HEAD first: python "${CONFIG.sharedScripts}/fetch_copilot_reviews.py" --owner ${input.owner} --repo ${input.repo} --pr-number ${input.prNumber}. This lists every Copilot review across all commits newest-first; only count entries whose commit_id starts with ${head}. If the newest such HEAD-scoped Copilot review is the out-of-usage notice above -> return the down result and stop. A notice on any earlier commit is NOT down: ignore it and continue. With no Copilot review on HEAD, skip a duplicate request: python "${CONFIG.sharedScripts}/check_pending_reviews.py" --owner ${input.owner} --repo ${input.repo} --pr-number ${input.prNumber} --user copilot. Exit 0 means a request is already pending; otherwise request one:\n` +
1372
1361
  ` ${REVIEWER_GATE_SENTINEL}gh api --method POST repos/${input.owner}/${input.repo}/pulls/${input.prNumber}/requested_reviewers -f 'reviewers[]=copilot-pull-request-reviewer[bot]'\n` +
1373
- `2. Poll for Copilot's review on HEAD ${head}: up to ${CONFIG.copilotMaxPolls} attempts, 360 seconds apart (wait each 360-second interval inside this turn with the Monitor tool, per the WAITS AND POLLS rule above; if the attempt budget is spent with no review on HEAD, return down: true). Each attempt: python "${CONFIG.sharedScripts}/fetch_copilot_reviews.py" --owner ${input.owner} --repo ${input.repo} --pr-number ${input.prNumber} for the top-level review state, plus gh api "repos/${input.owner}/${input.repo}/pulls/${input.prNumber}/comments" --paginate --slurp for inline comment ids (Copilot's login contains "copilot", case-insensitive). Only count entries whose commit_id starts with ${head}.\n` +
1362
+ `2. Poll for Copilot's review on HEAD ${head}: up to ${CONFIG.copilotMaxPolls} attempts, 360 seconds apart (wait each 360-second interval inside this turn with the Monitor tool, per the WAITS AND POLLS rule above; if the attempt budget is spent with no review on HEAD, return the full down result {sha:${'`'}${head}${'`'}, clean:false, down:true, findings:[]}). Each attempt: python "${CONFIG.sharedScripts}/fetch_copilot_reviews.py" --owner ${input.owner} --repo ${input.repo} --pr-number ${input.prNumber} for the top-level review state, plus gh api "repos/${input.owner}/${input.repo}/pulls/${input.prNumber}/comments" --paginate --slurp for inline comment ids (Copilot's login contains "copilot", case-insensitive). Only count entries whose commit_id starts with ${head}.\n` +
1374
1363
  ` - Out-of-usage notice on HEAD -> return the down result above (clean:true, down:true) and stop.\n` +
1375
1364
  ` - Copilot review present on HEAD whose state is APPROVED, or COMMENTED with no inline findings -> a clean pass: return {sha:${'`'}${head}${'`'}, clean:true, down:false, findings:[]}.\n` +
1376
1365
  ` - Copilot findings on HEAD -> return them (each with its inline comment id in replyToCommentId; category 'code-standard' for pure CODE_RULES/style violations with no behavioral impact, 'bug' otherwise), clean:false, down:false.\n` +
@@ -1432,20 +1421,22 @@ async function repairConvergence(head, failures) {
1432
1421
 
1433
1422
  /**
1434
1423
  * Pre-flight conflict resolution: when the PR branch conflicts with its base,
1435
- * rebase it clean before the bug checks run — check (Explore probes mergeability)
1436
- * -> edit (clean-coder rebases and resolves, no push) -> verify (code-verifier
1437
- * binds a verdict to the rebased tree) -> commit (clean-coder force-with-lease
1438
- * pushes). Returns the post-rebase HEAD so the first converge round runs its
1439
- * lenses on the conflict-free diff. A non-conflicting PR, a rebase the edit step
1440
- * declined, or a failed verdict returns the unchanged HEAD so the run proceeds to
1441
- * the bug checks unchanged. A mid-run conflict (origin/main advancing later) is
1442
- * still caught by the FINALIZE convergence repair, which also rebases.
1424
+ * rebase it clean before the bug checks run — edit (clean-coder rebases and
1425
+ * resolves, no push) -> verify (code-verifier binds a verdict to the rebased
1426
+ * tree) -> commit (clean-coder force-with-lease pushes). The conflict decision
1427
+ * comes from the merged 'preflight-git' probe the caller already ran, so this
1428
+ * function spawns no mergeability agent of its own. Returns the post-rebase
1429
+ * HEAD so the first converge round runs its lenses on the conflict-free diff.
1430
+ * A non-conflicting PR, a rebase the edit step declined, or a failed verdict
1431
+ * returns the unchanged HEAD so the run proceeds to the bug checks unchanged.
1432
+ * A mid-run conflict (origin/main advancing later) is still caught by the
1433
+ * FINALIZE convergence repair, which also rebases.
1443
1434
  * @param {string} head PR HEAD SHA before any rebase
1435
+ * @param {boolean} isConflicting the isMergeConflicting decision over the preflight-git result
1444
1436
  * @returns {Promise<string>} the HEAD SHA after a successful rebase push, or the unchanged head
1445
1437
  */
1446
- async function resolveMergeConflicts(head) {
1447
- const mergeState = await runGitTask('check-merge-conflicts', head)
1448
- if (!isMergeConflicting(mergeState)) return head
1438
+ async function resolveMergeConflicts(head, isConflicting) {
1439
+ if (!isConflicting) return head
1449
1440
  log(`Pre-flight: ${prCoordinates} conflicts with origin/main — rebasing clean before the bug checks`)
1450
1441
  const editResult = await runCodeEditorTask('conflict-edit', { head })
1451
1442
  if (editResult?.rebased !== true) return head
@@ -1655,24 +1646,24 @@ let reuseNote = null
1655
1646
  let reviewerAvailability = null
1656
1647
  const deferredPrs = []
1657
1648
 
1658
- const preflightHead = await runGitTask('resolve-head')
1659
- if (isResolvedHeadUsable(preflightHead?.sha)) {
1660
- await resolveMergeConflicts(preflightHead.sha)
1649
+ const preflight = await runGitTask('preflight-git')
1650
+ if (isResolvedHeadUsable(preflight?.sha)) {
1651
+ head = await resolveMergeConflicts(preflight.sha, isMergeConflicting(preflight))
1661
1652
  }
1662
1653
 
1663
1654
  log('Reuse pass: scanning the full diff for certain, behaviorally identical, autonomously implementable reuse improvements before convergence')
1664
- const reuseHeadResult = await runGitTask('resolve-head')
1665
- const reuseHead = reuseHeadResult?.sha
1666
- if (isResolvedHeadUsable(reuseHead)) {
1667
- await runGitTask('prefetch-main')
1668
- const reuse = await runReuseAuditPass(reuseHead)
1655
+ if (isResolvedHeadUsable(head)) {
1656
+ const reuse = await runReuseAuditPass(head)
1669
1657
  const reuseFindings = reuse?.findings || []
1670
1658
  if (reuseFindings.length > 0) {
1671
1659
  log(`Reuse pass: ${reuseFindings.length} qualifying reuse improvement(s) — applying before convergence`)
1672
- const reuseFix = await applyFixes(reuseHead, reuseFindings, 'reuse-pass')
1660
+ const reuseFix = await applyFixes(head, reuseFindings, 'reuse-pass')
1673
1661
  reuseNote = reuseFix?.pushed === true
1674
1662
  ? `${reuseFindings.length} reuse improvement(s) applied before convergence (${reuseFix.newSha?.slice(0, SHA_COMPARISON_PREFIX_LENGTH)})`
1675
1663
  : `${reuseFindings.length} reuse improvement(s) identified before convergence but not landed — the code-review lens re-surfaces any that remain`
1664
+ if (reuseFix?.pushed === true) {
1665
+ head = isResolvedHeadUsable(reuseFix.newSha) ? reuseFix.newSha : null
1666
+ }
1676
1667
  } else {
1677
1668
  log('Reuse pass: no reuse case cleared all three criteria — proceeding to convergence')
1678
1669
  }
@@ -1684,13 +1675,14 @@ while (iterations < CONFIG.maxIterations) {
1684
1675
  iterations += 1
1685
1676
  if (phase === 'CONVERGE') {
1686
1677
  rounds += 1
1687
- const headResult = await runGitTask('resolve-head')
1688
- head = headResult?.sha
1689
1678
  if (!isResolvedHeadUsable(head)) {
1690
- log(`Round ${rounds}: resolve-head agent returned no SHA — retrying without spawning lenses`)
1679
+ const refreshedPreflight = await runGitTask('preflight-git')
1680
+ head = isResolvedHeadUsable(refreshedPreflight?.sha) ? refreshedPreflight.sha : null
1681
+ }
1682
+ if (!isResolvedHeadUsable(head)) {
1683
+ log(`Round ${rounds}: preflight-git agent returned no SHA — retrying without spawning lenses`)
1691
1684
  continue
1692
1685
  }
1693
- await runGitTask('prefetch-main')
1694
1686
  reviewerAvailability = await runReviewerAvailabilityCheck()
1695
1687
  const isBugbotDownPreSpawn = resolveReviewerDown(reviewerAvailability?.bugbot, input.bugbotDisabled || false)
1696
1688
  log(`Round ${rounds}: parallel Bugbot + code-review + bug-audit on ${head?.slice(0, 7)}`)
@@ -1703,6 +1695,7 @@ while (iterations < CONFIG.maxIterations) {
1703
1695
  const roundOutcome = resolveRoundOutcome(lenses)
1704
1696
  if (roundOutcome.allLensesDead) {
1705
1697
  log(`Round ${rounds}: every lens agent died — retrying without posting a clean artifact`)
1698
+ head = null
1706
1699
  continue
1707
1700
  }
1708
1701
  const findings = roundOutcome.findings
@@ -1730,10 +1723,12 @@ while (iterations < CONFIG.maxIterations) {
1730
1723
  : `fix lens landed no push for ${findings.length} finding(s) on HEAD ${head}`
1731
1724
  break
1732
1725
  }
1726
+ head = null
1733
1727
  continue
1734
1728
  }
1735
1729
  if (!roundOutcome.roundClean) {
1736
1730
  log(`Round ${rounds}: a lens reported not-clean with no findings on ${head?.slice(0, 7)} — re-converging without a clean artifact`)
1731
+ head = null
1737
1732
  continue
1738
1733
  }
1739
1734
  log(`Round ${rounds}: all lenses clean on ${head?.slice(0, 7)} — posting clean audit artifact`)
@@ -1790,6 +1785,7 @@ while (iterations < CONFIG.maxIterations) {
1790
1785
  : `copilot fix lens landed no push for ${copilotOutcome.findings.length} finding(s) on HEAD ${head}`
1791
1786
  break
1792
1787
  }
1788
+ head = null
1793
1789
  phase = 'CONVERGE'
1794
1790
  continue
1795
1791
  }
@@ -1817,6 +1813,7 @@ while (iterations < CONFIG.maxIterations) {
1817
1813
  }
1818
1814
  log(`Convergence check failed: ${convergenceOutcome.failures.join('; ')} — repairing then re-converging`)
1819
1815
  await repairConvergence(head, convergenceOutcome.failures)
1816
+ head = null
1820
1817
  phase = 'CONVERGE'
1821
1818
  continue
1822
1819
  }
@@ -17,8 +17,7 @@ from autoconverge_report_constants.render_report_constants import (
17
17
  DEFAULT_FINDING_CATEGORY,
18
18
  DEFAULT_FINDING_SEVERITY,
19
19
  DEFAULT_ISSUE_ICON,
20
- HTML_DOCTYPE,
21
- HTML_HEAD_TEMPLATE,
20
+ HTML_TITLE_AND_STYLE_TEMPLATE,
22
21
  HTML_STYLE_BLOCK,
23
22
  ISO_DATE_LENGTH,
24
23
  ISSUE_CLASS_FIELD_AFTER_LINES,
@@ -890,7 +889,9 @@ def render_report_html(
890
889
  generated_date: ISO date string derived from the journal timestamp.
891
890
 
892
891
  Returns:
893
- A complete HTML document string.
892
+ A page-content HTML string (a title, a style block, and the body
893
+ markup) with no surrounding <!DOCTYPE>, <html>, <head>, or <body>
894
+ tags, ready for the Artifact tool to wrap and publish.
894
895
  """
895
896
  short_sha_length = SHORT_SHA_LENGTH
896
897
  pr_number = pr_metadata.number
@@ -899,7 +900,7 @@ def render_report_html(
899
900
  final_sha_short = pr_metadata.final_sha[:short_sha_length]
900
901
  round_count = pr_metadata.round_count
901
902
 
902
- head_html = HTML_HEAD_TEMPLATE.format(
903
+ title_and_style_html = HTML_TITLE_AND_STYLE_TEMPLATE.format(
903
904
  pr_number=pr_number,
904
905
  style_block=HTML_STYLE_BLOCK,
905
906
  )
@@ -933,15 +934,10 @@ def render_report_html(
933
934
  )
934
935
 
935
936
  return (
936
- f"{HTML_DOCTYPE}\n"
937
- f"<html lang='en'>\n"
938
- f"{head_html}\n"
939
- f"<body>\n"
937
+ f"{title_and_style_html}\n"
940
938
  f'<div class="container">\n'
941
939
  f"{body_content}\n"
942
- f"</div>\n"
943
- f"</body>\n"
944
- f"</html>"
940
+ f"</div>"
945
941
  )
946
942
 
947
943
 
@@ -10,7 +10,7 @@ Each loop: a `code-quality-agent` (fresh context, all A–P audit categories) pr
10
10
 
11
11
  | File | Purpose |
12
12
  |---|---|
13
- | `SKILL.md` | Hub — pre-flight call, refusals, audit-posting protocol, progress checklist, and situation-to-reference table. Read this first. |
13
+ | `SKILL.md` | Hub — pre-flight call, refusals, the audit-posting step (applies the `post-audit-findings` skill), progress checklist, and situation-to-reference table. Read this first. |
14
14
  | `PROMPTS.md` | Spawn XML, A–P category bindings, outcome XML schemas. |
15
15
  | `CONSTRAINTS.md` | Invariants — what the loop must never violate. |
16
16
  | `EXAMPLES.md` | Exit scenarios: converged, cap-reached, stuck, refusal, mixed-outcome. |
@@ -278,7 +278,7 @@ cd into `<worktree_path>` before any git or file operation.
278
278
  [ ] git add + commit
279
279
  [ ] git push
280
280
  [ ] Per finding: atomically post the unified-template reply, then call resolve_thread (no yield between them)
281
- [ ] Publish fix summary via /doc-gist, capture URL
281
+ [ ] Publish fix summary via the Artifact tool, capture URL
282
282
  [ ] Append fix summary URL to parent review via add_reply_to_pull_request_comment
283
283
  [ ] Write fix outcomes XML
284
284
  </self_audit_checklist>
@@ -343,14 +343,15 @@ cd into `<worktree_path>` before any git or file operation.
343
343
  `loop_comment_index` entry alongside `finding_comment_id`, see
344
344
  [reference/obstacles/fix-resolve-thread.md](reference/obstacles/fix-resolve-thread.md)).
345
345
 
346
- 9. Publish the fix summary gist via `/doc-gist`. Pass the fix report
347
- (what was fixed, what was skipped, what was left unaddressed) as the
348
- gist body. Capture the returned gist URL.
346
+ 9. Write the fix summary (what was fixed, what was skipped, what was left
347
+ unaddressed) to a self-contained HTML file, load the `artifact-design`
348
+ skill, then publish it with the `Artifact` tool. Capture the returned
349
+ URL.
349
350
 
350
- 10. Append the fix summary gist URL (from step 9) to the parent review
351
+ 10. Append the fix summary URL (from step 9) to the parent review
351
352
  via `add_reply_to_pull_request_comment(commentId=<id>, body=...,
352
353
  owner=<O>, repo=<R>, pullNumber=<N>)`. The body carries the
353
- gist URL plus a one-line summary of fixes applied this loop.
354
+ artifact URL plus a one-line summary of fixes applied this loop.
354
355
 
355
356
  11. Write `.bugteam-pr<N>-loop<L>.fix-outcomes.xml` inside
356
357
  `<worktree_path>` (schema below) and return its path.
@@ -36,7 +36,8 @@ First match wins; respond with the quoted line exactly and stop:
36
36
  token `bugteam` (comma-separated, case-insensitive, whitespace-tolerant):
37
37
  `/bugteam is disabled via CLAUDE_REVIEWS_DISABLED.` The pre-flight script
38
38
  also exits 7 in this case so any caller invoking it directly halts on the
39
- same signal.
39
+ same signal. Gate semantics live in the `reviewer-gates` skill
40
+ ([../reviewer-gates/SKILL.md](../reviewer-gates/SKILL.md)).
40
41
  - **No PR or upstream diff.** `No PR or upstream diff. /bugteam needs a target.`
41
42
  - **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before
42
43
  /bugteam.`
@@ -46,74 +47,26 @@ First match wins; respond with the quoted line exactly and stop:
46
47
 
47
48
  ## Audit posting
48
49
 
49
- Every internal audit pass (CLEAN or DIRTY) ends with one call to
50
- `post_audit_thread.py`. The script POSTs a single review to
51
- `/repos/{owner}/{repo}/pulls/{N}/reviews` with `event=APPROVE` on CLEAN
52
- (the request event; GitHub stores it as `state=APPROVED`; empty
53
- `comments[]`, body documents "no findings") or
54
- `event=REQUEST_CHANGES` on DIRTY (one inline anchored comment per
55
- finding; each becomes its own resolvable thread). The mandate applies
56
- whether bugteam runs inside `/pr-converge` or standalone.
57
-
58
- **Self-PR auto-toggle.** GitHub rejects both `APPROVE` and
59
- `REQUEST_CHANGES` reviews with HTTP 422 when the authenticated identity
60
- matches the PR author ("Cannot approve/request changes on your own pull
61
- request"). `post_audit_thread.py` detects this case via `gh api user` +
62
- `gh api repos/<o>/<r>/pulls/<n>` and auto-resolves an alternate gh
63
- account's token for the reviews POST — the active `gh auth` account is
64
- not mutated; only the bearer token sent on the request changes. After
65
- the POST the active account is still whoever it was before, so no
66
- "swap back" step is needed.
67
-
68
- Configuration:
69
-
70
- - `GH_TOKEN` / `GITHUB_TOKEN` env vars take precedence over the toggle.
71
- Set them when you need to pin a specific reviewer identity by token
72
- rather than by account login.
73
- - `BUGTEAM_REVIEWER_ACCOUNT` env var names which authenticated alternate
74
- to prefer when a toggle is needed (for example,
75
- `BUGTEAM_REVIEWER_ACCOUNT=jl-cmd`). When unset, the script falls back
76
- to the first alternate account `gh auth status` reports.
77
- - The named alternate must be logged in (`gh auth login -h github.com -u
78
- <login>`) before the audit skill runs. The script exits 1 with a
79
- pointing-at-`gh auth login` message when self-PR is detected and no
80
- usable alternate is authenticated.
81
-
82
- ```
83
- python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/post_audit_thread.py" \
84
- --skill bugteam \
85
- --owner <owner> \
86
- --repo <repo> \
87
- --pr-number <N> \
88
- --commit <head_sha> \
89
- --state <CLEAN|DIRTY> \
90
- --findings-json <path>
91
- ```
92
-
93
- `--findings-json` points to a JSON file whose root is a list of objects
94
- shaped `{path, line, side, severity, description, fix_summary}`. The
95
- audit agent's persisted finding output maps as follows: finding `file`
96
- → `path`, and the agent's `failure_mode` field carries both the failure
97
- narrative AND the `Fix:` / `Validation:` text per
98
- [`agents/code-quality-agent.md`](../../agents/code-quality-agent.md)
99
- ("The `failure_mode` field is the audit-to-fix handoff"). Split
100
- `failure_mode` at the literal `Fix:` heading: the prefix (the failure
101
- narrative) becomes `description`, and the suffix starting at `Fix:`
102
- (including the trailing `Validation:` clause) becomes `fix_summary`.
103
- When the agent omits the `Fix:` heading on a given finding, write the
104
- full `failure_mode` text to BOTH `description` and `fix_summary` so the
105
- script's body template (`INLINE_COMMENT_BODY_TEMPLATE` in
106
- [`_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py`](../../_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py))
107
- still renders coherently. Set `side="RIGHT"` for every entry. On CLEAN,
108
- pass an empty array (`[]`) so the script posts an APPROVE review
109
- (GitHub stores it as `state=APPROVED`) with a "no findings" summary and
110
- zero inline comments.
111
-
112
- Exit codes: `0` on success (emits the new review's `html_url` to
113
- stdout); `1` on user input error; `2` on retry exhaustion (1s / 4s /
114
- 16s backoff across four attempts total). Exit 2 is a hard blocker; the
115
- lead halts the loop and exits `error: post_audit_thread retry
116
- exhausted` without retrying.
50
+ Every internal audit pass (CLEAN or DIRTY) ends with one posted GitHub PR
51
+ review; the mandate applies whether bugteam runs inside `/pr-converge` or
52
+ standalone. Apply the `post-audit-findings` skill
53
+ ([../post-audit-findings/SKILL.md](../post-audit-findings/SKILL.md)) with
54
+ `--skill bugteam`: it covers the findings-JSON mapping (the `failure_mode`
55
+ split at the literal `Fix:` heading), the anchored-vs-unanchored partition,
56
+ the `post_audit_thread.py` invocation, the self-PR reviewer toggle
57
+ (`BUGTEAM_REVIEWER_ACCOUNT`), the exit codes, and the id harvest.
58
+
59
+ Bugteam-only obligations:
60
+
61
+ - The lead runs the posting step; the FIX teammate waits for the harvested
62
+ ids before replying or resolving.
63
+ - Record each harvested `{finding_comment_id, finding_comment_url,
64
+ thread_node_id}` triple into `loop_comment_index` (per-loop scope; see
65
+ [reference/team-setup.md](reference/team-setup.md) § Loop state block) so
66
+ the matching FIX action owns the reply-and-resolve unit.
67
+ - Exit 2 from `post_audit_thread.py` is a hard blocker: the lead halts the
68
+ loop and exits `error: post_audit_thread retry exhausted` without
69
+ retrying.
117
70
 
118
71
  ## Progress checklist
119
72
 
@@ -143,13 +96,13 @@ end-to-end mental model before starting Step 0.
143
96
  | `--bugbot-retrigger` flag behavior | [reference/team-setup.md](reference/team-setup.md) |
144
97
  | AUDIT action and code-rules pre-audit gate, pre-cycle walk, cycle decision tree | [reference/audit-and-teammates.md](reference/audit-and-teammates.md) |
145
98
  | FIX action and verify-push semantics | [reference/audit-and-teammates.md](reference/audit-and-teammates.md) |
146
- | Posting the end-of-pass audit review via `post_audit_thread.py` (APPROVE on CLEAN — the request event; GitHub stores it as `state=APPROVED` — REQUEST_CHANGES with inline anchored comments on DIRTY) | [§ Audit posting](#audit-posting) |
99
+ | Posting the end-of-pass audit review (APPROVE on CLEAN, REQUEST_CHANGES with inline anchored comments on DIRTY) | [§ Audit posting](#audit-posting), which applies [../post-audit-findings/SKILL.md](../post-audit-findings/SKILL.md) |
147
100
  | Posting per-finding fix replies via GitHub MCP `add_reply_to_pull_request_comment` (rendered with the unified template at [`_shared/pr-loop/audit-reply-template.md`](../../_shared/pr-loop/audit-reply-template.md)) | [reference/github-pr-reviews.md](reference/github-pr-reviews.md) |
148
- | Teardown, PR description rewrite via `pr-description-writer`, permission revoke, final report | [reference/teardown-publish-permissions.md](reference/teardown-publish-permissions.md) |
101
+ | Teardown, PR description rewrite via `pr-description-writer`, permission revoke, final report | [../pr-loop-lifecycle/reference/teardown-publish-permissions.md](../pr-loop-lifecycle/reference/teardown-publish-permissions.md) |
149
102
  | Spawn-prompt XML, A–P category bindings, outcome XML schemas | [PROMPTS.md](PROMPTS.md) |
150
103
  | Per-category audit content (sub-buckets, decision criteria, ready-to-send Variant C templates) | `$HOME/.claude/audit-rubrics/{category_rubrics,prompts}/` |
151
104
  | Invariants and design rationale | [CONSTRAINTS.md](CONSTRAINTS.md), [reference/design-rationale.md](reference/design-rationale.md) |
152
- | Audit-contract finding shape (Shape A / B), Haiku secondary, post-fix self-audit | [reference/audit-contract.md](reference/audit-contract.md) |
105
+ | Audit-contract finding shape (Shape A / B), Haiku secondary, post-fix self-audit | [../../_shared/pr-loop/audit-contract.md](../../_shared/pr-loop/audit-contract.md) |
153
106
  | Exit-scenario examples (converged, cap-reached, stuck, refusal, mixed-outcome) | [EXAMPLES.md](EXAMPLES.md) |
154
107
  | Doc URLs and verbatim quotes | [sources.md](sources.md) |
155
108
  | Historical Copilot gap analysis (superseded) | [reference/copilot-gap-analysis.md](reference/copilot-gap-analysis.md) |
@@ -7,11 +7,9 @@ Expanded workflow detail for the `bugteam` skill. Load a file from this director
7
7
  | File | Purpose |
8
8
  |---|---|
9
9
  | `README.md` | Index of all files in this directory with one-line domain summaries. |
10
- | `team-setup.md` | Permissions grant, PR scope resolution, run name, temp dir, and loop state. |
10
+ | `team-setup.md` | Permissions grant, PR scope resolution (applies the `pr-scope-resolve` skill), run name, temp dir, and loop state. |
11
11
  | `audit-and-teammates.md` | Pre-audit CODE_RULES gate, full cycle numbering, AUDIT and FIX action detail. |
12
- | `audit-contract.md` | Finding shape (Shape A / B), Haiku secondary merge rules, post-fix self-audit. |
13
12
  | `github-pr-reviews.md` | Per-loop review posting, `jq`+`gh api` payloads, inline anchors, fallbacks, REST endpoints. |
14
- | `teardown-publish-permissions.md` | Teardown steps, PR description rewrite via `pr-description-writer`, permission revoke, final report. |
15
13
  | `design-rationale.md` | Why clean-room subagents, when `/bugteam` applies, refusal reasons. |
16
14
  | `copilot-gap-analysis.md` | Historical gap analysis (reference only). |
17
15
 
@@ -8,7 +8,7 @@ Expanded material that used to live inline in `SKILL.md`. Load a file when the o
8
8
  | [`team-setup.md`](team-setup.md) | Permissions grant (`CLAUDE_SKILL_DIR`), PR scope, run name / temp dir / loop state |
9
9
  | [`github-pr-reviews.md`](github-pr-reviews.md) | Per-loop reviews, `jq` + `gh api` payloads, anchors, fallbacks, REST endpoints |
10
10
  | [`audit-and-teammates.md`](audit-and-teammates.md) | Pre-audit gate, full cycle numbering, AUDIT and FIX actions |
11
- | [`teardown-publish-permissions.md`](teardown-publish-permissions.md) | Utility scripts note, teardown, PR description rewrite, revoke, final report |
11
+ | [`../../pr-loop-lifecycle/reference/teardown-publish-permissions.md`](../../pr-loop-lifecycle/reference/teardown-publish-permissions.md) | Utility scripts note, teardown, PR description rewrite, revoke, final report |
12
12
 
13
13
  Canonical documentation quotes: [`../sources.md`](../sources.md).
14
14
 
@@ -153,7 +153,7 @@ Agent(
153
153
 
154
154
  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
155
 
156
- 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.
156
+ 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; the mechanics follow the `pr-fix-protocol` skill ([`../../pr-fix-protocol/SKILL.md`](../../pr-fix-protocol/SKILL.md)), which frames the shared 13-step sequence in [`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md) (step 12 carries the exact reply-and-resolve sequence). Same identity model as bugfind: teammate posts; lead waits.
157
157
 
158
158
  After replies, the teammate writes outcome XML (schema in [`../PROMPTS.md`](../PROMPTS.md)).
159
159
 
@@ -1,6 +1,6 @@
1
1
  # Publish fix summary
2
2
 
3
- Publish fix summary HTML via /doc-gist with commit SHA, files, per-fix descriptions
3
+ Publish fix summary HTML via the Artifact tool with commit SHA, files, per-fix descriptions
4
4
 
5
5
  ## Self-population
6
6
 
@@ -8,7 +8,7 @@ Bugteam-specific utilities (preflight, fix_hookspath, grant, revoke) live in
8
8
  the skill-local [`scripts/`](../scripts/) directory. Shared utilities remain in
9
9
  [`_shared/pr-loop/scripts/`](../../_shared/pr-loop/scripts/) (run, do not paste
10
10
  into context). Utility scripts are **executed**, not loaded as primary context
11
- ([`sources.md`](sources.md) § Progressive disclosure and utility scripts).
11
+ ([`sources.md`](../sources.md) § Progressive disclosure and utility scripts).
12
12
 
13
13
  ```bash
14
14
  python "${CLAUDE_SKILL_DIR}/scripts/bugteam_preflight.py"
@@ -53,7 +53,7 @@ the auto-remediation only applies to the `core.hooksPath` failure mode.
53
53
  Before spawning any subagents, grant the session write access to the project's `.claude/**` tree:
54
54
 
55
55
  ```bash
56
- python "${CLAUDE_SKILL_DIR}/scripts/grant_project_claude_permissions.py"
56
+ python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/grant_project_claude_permissions.py"
57
57
  ```
58
58
 
59
59
  `${CLAUDE_SKILL_DIR}` is a Claude Code host-managed token, pre-substituted by the runtime before any shell sees it. Unlike `${TMPDIR}` and similar shell parameter expansions, it does not depend on the shell’s expansion semantics, so it behaves the same on Unix and Windows shells.
@@ -64,11 +64,12 @@ This is the **first** action of every `/bugteam` invocation, before any subagent
64
64
 
65
65
  ## Step 1 — Resolve PR scope (detail)
66
66
 
67
- Same resolution path as `/findbugs`:
68
-
69
- 1. Call `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` to fetch PR metadata; capture `number`, `headRefName`, `baseRefName`, and `url` from the response. Falls back to the merge-base diff path when no PR exists.
70
- 2. Fall back to `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`.
71
- 3. Neither refuse per refusal cases in `SKILL.md`.
67
+ Apply the `pr-scope-resolve` skill
68
+ ([../../pr-scope-resolve/SKILL.md](../../pr-scope-resolve/SKILL.md)) with
69
+ caller `bugteam`. Its resolution ladder hands back `owner`, `repo`, `number`,
70
+ `head_ref`, `base_ref`, `url`, and `head_sha`; when no PR and no upstream
71
+ diff exist, respond exactly `No PR or upstream diff. /bugteam needs a
72
+ target.` and stop.
72
73
 
73
74
  Capture `<owner>/<repo>`, head branch, base branch, PR number, PR URL. This scope persists across every loop — `/bugteam` runs to completion from the single up-front confirmation.
74
75
 
@@ -9,9 +9,6 @@ Python scripts executed by the bugteam lead or teammates at runtime. These are n
9
9
  | `bugteam_preflight.py` | Run pytest and optional `pre-commit` before the first loop. Skips pytest when `BUGTEAM_PREFLIGHT_SKIP=1` or no test files exist. |
10
10
  | `bugteam_fix_hookspath.py` | Auto-remediate a stale `core.hooksPath` override, set the canonical global value, re-run preflight. |
11
11
  | `bugteam_code_rules_gate.py` | Run `validate_content` from `code_rules_enforcer.py` on PR-scoped files. Exit 1 on mandatory rule failures. |
12
- | `grant_project_claude_permissions.py` | Grant Edit/Write/Read on `cwd/.claude/**` in `~/.claude/settings.json`. |
13
- | `revoke_project_claude_permissions.py` | Remove the matching grant entries from `~/.claude/settings.json`. |
14
- | `_bugteam_permissions_common.py` | Shared helpers for grant/revoke (atomic JSON writes, settings sections). |
15
12
  | `windows_safe_rmtree.py` | Remove a directory tree on Windows by stripping ReadOnly attributes and retrying on failure. |
16
13
  | `probe_code_rules_enforcer_check.py` | Load `code_rules_enforcer.py` and invoke a named check function against a fixture file. |
17
14
  | `reflow_skill_md.py` | Reflow the bugteam SKILL.md body to fit line-length limits. |
@@ -23,9 +20,6 @@ Python scripts executed by the bugteam lead or teammates at runtime. These are n
23
20
  | `test_bugteam_preflight.py` | `bugteam_preflight.py` |
24
21
  | `test_bugteam_code_rules_gate.py` | `bugteam_code_rules_gate.py` |
25
22
  | `test_bugteam_fix_hookspath.py` | `bugteam_fix_hookspath.py` |
26
- | `test_bugteam_permissions_common.py` | `_bugteam_permissions_common.py` |
27
- | `test__bugteam_permissions_common.py` | Internal helpers in `_bugteam_permissions_common.py` |
28
- | `test_agent_config_carveout.py` | `.claude/**` grant/revoke carveout logic |
29
23
  | `test_probe_code_rules_enforcer_check.py` | `probe_code_rules_enforcer_check.py` |
30
24
  | `test_windows_safe_rmtree.py` | `windows_safe_rmtree.py` |
31
25
 
@@ -7,10 +7,6 @@ Scripts in this directory are **executed** by the lead or teammates. They are no
7
7
  | `bugteam_preflight.py` | Run pytest (when configured) and optional `pre-commit` before `/bugteam`. |
8
8
  | `bugteam_fix_hookspath.py` | Auto-remediate a stale local `core.hooksPath` override, set canonical global value, re-run `bugteam_preflight.py`. Invoked by Claude when preflight reports a `core.hooksPath` failure. |
9
9
  | `bugteam_code_rules_gate.py` | Run `validate_content` from `code-rules-enforcer.py` on PR-scoped files (`git diff` vs merge-base). Exit `1` if any mandatory rule fails. Invoked **before each audit**; the fixer clears it before the auditor runs. |
10
- | `grant_project_claude_permissions.py` | Idempotent grant of Edit/Write/Read on `cwd/.claude/**` into `~/.claude/settings.json`. |
11
- | `revoke_project_claude_permissions.py` | Removes the matching grant entries from `~/.claude/settings.json`. |
12
- | `test_claude_permissions_common.py` | Pytest module for path normalization and glob-metacharacter guards in `_claude_permissions_common.py`. |
13
- | `_claude_permissions_common.py` | Shared helpers for the grant/revoke scripts (atomic JSON writes, settings sections). |
14
10
  | `windows_safe_rmtree.py` | Recursively remove a directory tree on Windows by stripping ReadOnly attributes and retrying the failing syscall. Invoked from SKILL.md Step 4 to delete `<run_temp_dir>` after teardown. |
15
11
  | `probe_code_rules_enforcer_check.py` | Dynamically load `~/.claude/hooks/blocking/code_rules_enforcer.py` and invoke a named check function against a fixture file. Used by the historical Copilot gap-analysis investigation as a verification shape (see `reference/copilot-gap-analysis.md`). |
16
12
 
@@ -9,7 +9,6 @@ Python package of named constants imported by the bugteam scripts. Each module h
9
9
  | `bugteam_preflight_constants.py` | `bugteam_preflight.py` — env var name, hooks path suffix, exit codes, ignore dirs, argument tuples, config filenames. |
10
10
  | `bugteam_code_rules_gate_constants.py` | `bugteam_code_rules_gate.py` — gate-related path and exit-code constants. |
11
11
  | `bugteam_fix_hookspath_constants.py` | `bugteam_fix_hookspath.py` — canonical hooks path, remediation message strings. |
12
- | `claude_permissions_common_constants.py` | `_bugteam_permissions_common.py` — settings JSON keys, glob patterns for the grant/revoke scripts. |
13
12
  | `probe_code_rules_enforcer_check_constants.py` | `probe_code_rules_enforcer_check.py` — enforcer module path and function name constants. |
14
13
  | `reflow_skill_md_constants.py` | `reflow_skill_md.py` — line-length and formatting constants. |
15
14
  | `windows_safe_rmtree_constants.py` | `windows_safe_rmtree.py` — retry count and wait constants. |