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
package/CLAUDE.md CHANGED
@@ -1,54 +1,28 @@
1
1
  # Claude Development Assistant
2
2
 
3
- The user delegates execution to you and expects zero manual steps unless strictly necessary. Execute every command you can directly. Only instruct the user to do something manually when you are technically unable to do it yourself. When a task involves credentials or other sensitive input, display a minimal secure UI (e.g., a password dialog) to collect it rather than asking the user to paste it into chat or run the command themselves. When direction is ambiguous, use AskUserQuestion to clarify before acting.
3
+ The user delegates execution to you and expects zero manual steps unless strictly necessary. Execute every command you can directly. Only instruct the user to do something manually when you are technically unable to do it yourself. When a task involves credentials or other sensitive input, display a minimal secure UI (e.g., a password dialog) to collect it rather than asking the user to paste it into chat or run the command themselves. When direction is ambiguous, use AskUserQuestion to clarify before acting.
4
4
 
5
5
  ## Code Rules
6
6
  @~/.claude/docs/CODE_RULES.md
7
7
 
8
+ When a UNC path is mapped to a drive letter, ALWAYS prefer the drive letter and NEVER use UNC.
9
+
10
+ ## GOTCHAS
11
+ When making code changes, make sure you are working in the proper worktree path for the task at hand.
12
+ When writing to an existing file, you must either EDIT the file, or remove it and THEN re-write it if it's truly a full re-write.
13
+
8
14
  ## File-Global Constants
9
15
 
10
16
  **file_global_constants_use_count:** Every module-level constant in production code outside `config/` must be referenced by at least two methods, functions, or classes in the same file. One reference → move to `config/` and import as a local alias. Zero references → delete (dead code). Test files are exempt.
11
17
 
12
18
  Full rule including the decision table, examples, and exemption details: [`packages/claude-dev-env/rules/file-global-constants.md`](rules/file-global-constants.md).
13
19
 
14
- ## SOLID Principles
15
-
16
- **SRP (Single Responsibility)** always applies: one reason to change per function, class, or module — regardless of paradigm.
17
-
18
- **OCP, LSP, ISP, DIP** apply where two or more concrete implementations already share a contract. With a single concretion, Right-Sized Engineering takes precedence: use concrete classes, functions when no state, and direct imports. Refactor toward OCP/DIP at the commit that introduces the second concrete implementation.
19
-
20
- Full rule including the reconciliation with Right-Sized Engineering, misapplication signals, and when-it-adds-value criteria: [`packages/claude-dev-env/docs/CODE_RULES.md`](docs/CODE_RULES.md) §7.5.
21
-
22
- ## Core Philosophy
20
+ ## Test Philosophy
23
21
 
24
- **TDD IS NON-NEGOTIABLE.** Build it right, build it simple. Maintainable > Clever.
22
+ When writing tests, always write tests that actually test the behavior of the function against actual, real data and environments.
25
23
 
26
- ## Expectations for Claude
27
-
28
- 1. **ALWAYS FOLLOW TDD** - No production code without failing test
29
- 2. **MANDATORY SELF-CHECK before proposing** - See protocol below
30
- 3. Assess refactoring after every green
31
-
32
- **BEFORE proposing plans/implementation:**
33
-
34
- ☐ "Is this KISS?" (simplest? unnecessary complexity?)
35
- ☐ "Over-engineering?" (multiple files? premature abstractions?)
36
- ☐ Test infrastructure? (ONE file, functions, YAGNI)
37
- ☐ Tests add value? (no existence checks, no constant tests)
38
- ☐ Files (proper modules, correct dirs, no empty __init__.py)
39
- ☐ Quality (DRY, types complete, no Any/any)
24
+ When writing tests, always ensure you utilize the production code paths instead of duplicating explicitly for the test.
40
25
 
41
26
  ## Additional Non-overlapping Rules
42
27
 
43
28
  - **task_scope:** Match every action to what was explicitly requested. When intent is ambiguous, research official docs and present options via AskUserQuestion before making any changes. Proceed with edits only on explicit instruction.
44
-
45
- ## Tool Policies
46
- - **context7:** Before writing code using any library/framework/SDK/API, call `resolve-library-id` then `query-docs` via Context7 MCP. Use the fetched docs to write code. Applies to all libs including React, Next.js, Django, Express, Prisma.
47
- - **gh MCP:** Always use `mcp__plugin_github_github__*` tools for any GitHub operations (branches, PRs, file operations). Do not use the `Bash` tool to invoke `gh` or `git` CLI for GitHub operations.
48
-
49
- ## Compaction
50
- When compacting, always preserve:
51
- - Active task and current goal
52
- - Full list of modified files
53
- - Any failing test names or error messages
54
- - Current git branch and PR state
@@ -0,0 +1,147 @@
1
+ # Audit reply template
2
+
3
+ Canonical reply shape for every orchestrator-to-thread reply posted by the PR-loop suite (`pr-converge`, `bugteam`, `qbug`, and the `clean-coder` agent). Every reply Claude posts to an unresolved review thread on a draft PR uses this template.
4
+
5
+ Read this doc before authoring any code that posts a reply. The template is the contract emitted by every `clean-coder` reply path; the audit-skill wiring (`bugteam`, `qbug`, `pr-converge`) reads it before authoring a reply.
6
+
7
+ This doc has two surfaces, called out separately so consumers do not conflate them: the **reply template** (this section and below) shapes the body Claude posts back to a single review thread; the **audit body skeleton** in [Relationship to the audit review body](#relationship-to-the-audit-review-body) shapes the parent review `post_audit_thread.py` posts at audit time. The reply-template consumers are the four skills/agents listed above (read-only `findbugs` is excluded — it posts an audit review via `post_audit_thread.py` but never authors thread replies). The audit-body-skeleton consumers include `findbugs` alongside `bugteam` and `qbug` because all three skills post audit reviews via the same script.
8
+
9
+ ## Provenance
10
+
11
+ The template mirrors Anthropic's `claude[bot]` reply structure observed on `anthropics/claude-code`. Reference example: PR `anthropics/claude-code#10826`, inline comment `2483980211`. Reading that thread shows the structural anchors this template captures: a status header line, a horizontal-rule separator, an `<action_heading> ✅` section, a plain-language explanation, anchored `**`<file>:<line>`:**` bullets, and a closing paragraph.
12
+
13
+ ## When the template applies
14
+
15
+ Every reply path uses the same skeleton. Two paths exist; both produce a reply with the structure below.
16
+
17
+ | Path | When the orchestrator picks it | Code-side action |
18
+ |---|---|---|
19
+ | Fix | Thread classified `still_applies`. Code change addresses the finding. | `clean-coder` commits the fix, pushes, then replies. |
20
+ | No-longer-applies | Thread classified `no_longer_applies`. Concern is moot under the current code (file removed, intent satisfied differently, refactor obviated the concern). | No code change. Orchestrator posts the reply directly. |
21
+
22
+ ## Template skeleton
23
+
24
+ ```
25
+ **Claude finished @<reviewer>'s task** —— <status_line>
26
+
27
+ ---
28
+ ### <action_heading> ✅
29
+
30
+ <1–2 paragraph plain-language explanation>
31
+
32
+ **`<file>:<line>`:**
33
+ - <bullet describing change or rationale>
34
+ - <bullet describing change or rationale>
35
+
36
+ <closing paragraph>
37
+ ```
38
+
39
+ ### Placeholder reference
40
+
41
+ | Placeholder | Required value |
42
+ |---|---|
43
+ | `<reviewer>` | GitHub login of the reviewer whose thread the reply addresses (e.g., `cursor[bot]`, `copilot-pull-request-reviewer[bot]`, `claude[bot]`, the bugteam-account login, a human reviewer's login). |
44
+ | `<status_line>` | One of two fixed strings, see [Per-path variation](#per-path-variation). |
45
+ | `<action_heading>` | Per-path content, see [Per-path variation](#per-path-variation). |
46
+ | `<file>:<line>` | Path relative to repo root and the line number the reviewer anchored to. Multiple `**`<file>:<line>`:**` blocks are allowed when the reply spans more than one anchor in the same thread. |
47
+ | Bullets | Two or more bullets per anchor block. Each bullet is one sentence. |
48
+ | Closing paragraph | One paragraph that ties the bullets back to the reviewer's concern. Affirmative phrasing only. |
49
+
50
+ The separator between the header and `<action_heading>` is a Markdown horizontal rule (`---`) on its own line. The em-dash separator inside the header line is `——` (two em-dashes, U+2014 ×2). Both render correctly on GitHub.
51
+
52
+ ## Per-path variation
53
+
54
+ | Path | `<status_line>` | `<action_heading>` |
55
+ |---|---|---|
56
+ | Fix | `Fixed in <SHA>` (short SHA, 7 characters) | Finding-specific action verb. Example: `Replaced Any with concrete type`, `Renamed handle_request to dispatch_webhook`, `Added missing Raises: section`. |
57
+ | No longer applies | `This concern no longer applies` | Reason-specific. Example: `File removed in commit <SHA>`, `Intent satisfied via refactor in commit <SHA>`, `Concern superseded by upstream change`. |
58
+
59
+ ## Structural identity rule
60
+
61
+ The skeleton is identical across both paths. The only per-path differences are `<status_line>` and `<action_heading>`. Every other element is present in both paths:
62
+
63
+ - The header line with `**Claude finished @<reviewer>'s task** —— <status_line>` is present in both paths.
64
+ - The horizontal rule separator is present in both paths.
65
+ - The `### <action_heading> ✅` line is present in both paths.
66
+ - The plain-language explanation is present in both paths.
67
+ - The `**`<file>:<line>`:**` bullet blocks are present in both paths. On the fix path, bullets describe what changed. On the no-longer-applies path, bullets describe why the concern is moot at that anchor.
68
+ - The closing paragraph is present in both paths.
69
+
70
+ A reply that omits any of these elements does not satisfy the template.
71
+
72
+ ## Worked example — fix path
73
+
74
+ Reviewer thread (synthesized for this doc):
75
+
76
+ > `cursor[bot]` on `src/foo.py:42`:
77
+ > The `handle_request` function returns `Any`. Name the concrete return type so callers do not lose type information.
78
+
79
+ Reply posted by `clean-coder` after committing the fix at SHA `a3f9c12`:
80
+
81
+ ```markdown
82
+ **Claude finished @cursor[bot]'s task** —— Fixed in a3f9c12
83
+
84
+ ---
85
+ ### Replaced Any with concrete return type ✅
86
+
87
+ The reviewer's concern is correct: returning `Any` from a public function erases type information for every caller and defeats `mypy`'s ability to catch shape mismatches downstream. The fix names the concrete return type the function already produces.
88
+
89
+ **`src/foo.py:42`:**
90
+ - Changed the return annotation from `Any` to `RequestOutcome`.
91
+ - Renamed the function from `handle_request` to `dispatch_webhook` to comply with the banned-prefix rule (`handle_` is one of the banned function prefixes per `CODE_RULES.md`).
92
+ - Added a Google-style `Returns:` section to the docstring naming the new return type.
93
+
94
+ The function signature now matches its actual behavior, and `mypy --strict` reports zero errors on the touched file.
95
+ ```
96
+
97
+ ## Worked example — no-longer-applies path
98
+
99
+ Reviewer thread (synthesized for this doc):
100
+
101
+ > `copilot-pull-request-reviewer[bot]` on `src/legacy_adapter.py:88`:
102
+ > This compatibility shim should be removed once the upstream migration completes. Add a TODO with the planned removal date.
103
+
104
+ Reply posted by the orchestrator directly (no code change) after the upstream migration lands and removes the shim file entirely:
105
+
106
+ ```markdown
107
+ **Claude finished @copilot-pull-request-reviewer[bot]'s task** —— This concern no longer applies
108
+
109
+ ---
110
+ ### File removed in commit b8e2d4f ✅
111
+
112
+ The compatibility shim the reviewer flagged is no longer present in the tree. The upstream migration completed in commit `b8e2d4f`, and the same commit deleted `src/legacy_adapter.py` outright. There is no longer any shim to add a TODO to, and there is no longer any caller that imports from the removed module.
113
+
114
+ **`src/legacy_adapter.py:88`:**
115
+ - The anchored line lives in a file deleted by commit `b8e2d4f`.
116
+ - A repo-wide grep for `legacy_adapter` returns zero matches.
117
+ - The two former call sites (`src/api/router.py`, `src/api/middleware.py`) import from the consolidated module instead.
118
+
119
+ The thread can be resolved without further action; the reviewer's underlying concern is satisfied by the deletion rather than by the originally requested TODO.
120
+ ```
121
+
122
+ ## Relationship to the audit review body
123
+
124
+ The audit review body posted by `post_audit_thread.py` (consumers: `bugteam`, `findbugs`, `qbug`) shares the same header anchor pattern:
125
+
126
+ <!-- audit-body-skeleton:start -->
127
+ ```
128
+ **<Skill> audit completed** —— <state_label>
129
+
130
+ ---
131
+ ### <heading>
132
+
133
+ <summary paragraph>
134
+
135
+ **Findings:** <N> | **Severity:** <P0 count>P0 / <P1 count>P1 / <P2 count>P2
136
+
137
+ <optional collapsed details section per finding>
138
+ ```
139
+ <!-- audit-body-skeleton:end -->
140
+
141
+ The audit review body announces a complete audit pass; the reply template addresses one specific thread. They use the same `**Title** —— <status>` header convention so a reader scanning a PR sees consistent visual anchoring across both surfaces.
142
+
143
+ ## Cross-references
144
+
145
+ - [`audit-contract.md`](audit-contract.md) — finding schema (Shape A / Shape B), adversarial second pass, post-fix self-audit, persistence layout. The fields in a Shape A finding (`file`, `line`, `failure_mode`) feed the placeholders in this template. Replies cite the same `<file>:<line>` anchors that the originating audit recorded.
146
+ - [`fix-protocol.md`](fix-protocol.md) — step 12 of the fix protocol describes the reply step and renders this template's full structure.
147
+ - [`gh-payloads.md`](gh-payloads.md) — MCP and REST endpoints used to post replies (`add_reply_to_pull_request_comment` and `post_fix_reply.py`). The transport is independent of the template; both transports accept the body string this template defines.
@@ -16,10 +16,31 @@
16
16
  9. **Stage by explicit path:** `git add <path>` for each modified file. Avoid `git add -A` and `git add .`.
17
17
  10. **Create one commit** summarizing the fixed findings. Let every git hook run. When a hook blocks the commit, capture stderr, mark every finding in this loop `status=hook_blocked`, and move to the next iteration without retrying this loop.
18
18
  11. **Push fast-forward:** `git push origin <branch>`. Verify `git fetch origin <branch> && git rev-parse origin/<branch>` matches `HEAD`.
19
- 12. **Reply inline** on each finding's comment thread using the [`gh-payloads.md`](gh-payloads.md) reply shape. Reply body is one of:
20
- - `Fixed in <short_sha>`
21
- - `Could not address this loop: <one-line reason>`
22
- - `Hook blocked the fix commit: <one-line summary>`
19
+ 12. **Reply + resolve, atomic per thread.** For each finding, post the reply and call `resolve_thread` as one logical action no yield to the orchestrator between them, no batching all replies before any resolves.
20
+
21
+ The reply body uses the unified template from [`audit-reply-template.md`](audit-reply-template.md). Skeleton (identical across all paths):
22
+
23
+ ```
24
+ **Claude finished @<reviewer>'s task** —— <status_line>
25
+
26
+ ---
27
+ ### <action_heading> ✅
28
+
29
+ <1–2 paragraph plain-language explanation>
30
+
31
+ **`<file>:<line>`:**
32
+ - <bullet describing change or rationale>
33
+ - <bullet describing change or rationale>
34
+
35
+ <closing paragraph>
36
+ ```
37
+
38
+ Per-path `<status_line>` / `<action_heading>`:
39
+ - `status=fixed`: `Fixed in <short_sha>` (7-char SHA) / finding-specific action verb (e.g., `Replaced Any with concrete type`).
40
+ - `status=could_not_address`: `Could not address this loop` / one-line reason text.
41
+ - `status=hook_blocked`: `Hook blocked the fix commit` / one-line hook summary.
42
+
43
+ Transport: post the reply via [`gh-payloads.md`](gh-payloads.md), then call `pull_request_review_write(method="resolve_thread", threadId=<thread_node_id>, ...)` for the same thread before moving to the next finding (this is the PR review thread node ID — `PRRT_kwDOxxx` — distinct from the numeric comment ID; harvest it at audit time when calling `get_review_comments`, see [`skills/bugteam/reference/obstacles/fix-resolve-thread.md`](../../skills/bugteam/reference/obstacles/fix-resolve-thread.md)).
23
44
  13. **Re-trigger reviewer** when the calling workflow specifies. Workflow-specific:
24
45
  - `pr-converge`: post `bugbot run` issue comment after every push (Cursor Bugbot)
25
46
  - `monitor-many`: post `bugbot run` issue comment AND call `requested_reviewers` API for Copilot
@@ -8,42 +8,29 @@ Build payloads as structured arguments to MCP tools. Body content passes as a st
8
8
 
9
9
  ## One review per loop
10
10
 
11
- Call `pull_request_review_write` once per audit loop. Payload: `event: "COMMENT"`, the review body, and one `comments[]` object per anchored finding.
12
-
13
- ```
14
- pull_request_review_write(
15
- method="create",
16
- event="COMMENT",
17
- body=review_body,
18
- commitID=head_sha,
19
- owner=owner,
20
- repo=repo,
21
- pullNumber=pull_number,
22
- comments=[
23
- {path: file_path, line: line_number, side: "RIGHT", body: finding_body}
24
- ]
25
- )
26
- ```
27
-
28
- Single-line anchors: `{path, line, side: "RIGHT", body}`. Multi-line anchors add `start_line` and `start_side: "RIGHT"`.
29
-
30
- Zero findings still post one review. Body line: `## /<workflow> loop <N> audit: 0P0 / 0P1 / 0P2 → clean`. `comments: []`.
31
-
32
- ## Review body template
33
-
34
- ```
35
- ## /<workflow> loop <N> audit: <P0>P0 / <P1>P1 / <P2>P2
36
-
37
- ### Findings without a diff anchor
38
- (only when needed)
39
- - **[severity] title** — <file>:<line> — <one-line description>
40
- ```
41
-
42
- `<workflow>` is the calling skill name (`bugteam`, `qbug`, `pr-converge`).
11
+ Posting the per-loop audit review is handled by
12
+ [`_shared/pr-loop/scripts/post_audit_thread.py`](scripts/post_audit_thread.py).
13
+ The script owns the review-create/POST/retry flow internally; callers no longer
14
+ build the GitHub reviews-API payload themselves. See
15
+ [`skills/bugteam/SKILL.md` § Audit posting](../../skills/bugteam/SKILL.md#audit-posting)
16
+ for the contract and [`skills/bugteam/PROMPTS.md`](../../skills/bugteam/PROMPTS.md)
17
+ for the AUDIT-step invocation shape.
18
+
19
+ ## Review body skeleton
20
+
21
+ The review body skeleton lives in
22
+ [`audit-reply-template.md`](audit-reply-template.md) between the
23
+ `<!-- audit-body-skeleton:start -->` and `<!-- audit-body-skeleton:end -->`
24
+ markers. `post_audit_thread.py` reads that skeleton at runtime and substitutes
25
+ its placeholders (`<Skill>`, `<state_label>`, `<heading>`, severity counts,
26
+ collapsed `<details>` block). Callers pass the skill name, state, commit SHA,
27
+ and findings JSON; the body shape is owned by the template.
43
28
 
44
29
  ## Reply to a finding
45
30
 
46
- Call `add_reply_to_pull_request_comment` with the finding comment ID and reply body:
31
+ Call `add_reply_to_pull_request_comment` with the finding comment ID and a
32
+ reply body rendered from
33
+ [`audit-reply-template.md`](audit-reply-template.md):
47
34
 
48
35
  ```
49
36
  add_reply_to_pull_request_comment(
@@ -55,30 +42,30 @@ add_reply_to_pull_request_comment(
55
42
  )
56
43
  ```
57
44
 
58
- ## Anchor fallback (line not in diff)
59
-
60
- Lines not in the PR diff cannot anchor an inline comment. Omit them from `comments[]` and list under the review body's `### Findings without a diff anchor` section. Outcome record per finding: `used_fallback="true"`, empty `finding_comment_id`, `finding_comment_url` = parent review URL.
45
+ The `body` follows the unified reply skeleton documented in
46
+ [`audit-reply-template.md` § Template skeleton](audit-reply-template.md#template-skeleton).
61
47
 
62
- ## Review POST failure fallback (issue comment)
48
+ ## Anchor fallback (line not in diff)
63
49
 
64
- When the review POST fails, call `add_issue_comment` with the full review body:
50
+ Lines not in the PR diff cannot anchor an inline comment. The AUDIT teammate
51
+ keeps such findings out of the findings JSON handed to
52
+ `post_audit_thread.py`, lists them in the audit outcome XML under `<finding>`
53
+ with an empty `finding_comment_id`, and surfaces them in the calling skill's
54
+ user-facing output (chat reply to the user) rather than in the PR review body.
65
55
 
66
- ```
67
- add_issue_comment(
68
- owner=owner,
69
- repo=repo,
70
- issueNumber=pull_number,
71
- body=fallback_body
72
- )
73
- ```
56
+ ## Review POST failure
74
57
 
75
- All findings in the loop record `used_fallback="true"`; `finding_comment_url` = issue comment URL.
58
+ There is no fallback path. `post_audit_thread.py` exits `2` on retry
59
+ exhaustion (four non-2xx responses across the built-in `1s / 4s / 16s` backoff)
60
+ and the orchestrator halts with `error: post_audit_thread retry exhausted`.
61
+ A hard blocker on the audit-posting path is a halt condition, not a degraded
62
+ flat-issue-comment fall-through.
76
63
 
77
64
  ## Endpoints
78
65
 
79
- - Review: `pull_request_review_write(method="create", ...)`
80
- - Reply: `add_reply_to_pull_request_comment(...)`
81
- - Fallback issue comment: `add_issue_comment(...)`
66
+ - Review: handled by `post_audit_thread.py` (POSTs to
67
+ `/repos/{owner}/{repo}/pulls/{N}/reviews` internally).
68
+ - Reply: `add_reply_to_pull_request_comment(...)`.
82
69
 
83
70
  ## SHA capture timing
84
71
 
@@ -15,18 +15,13 @@ from config.code_rules_gate_constants import (
15
15
  ALL_CODE_FILE_EXTENSIONS,
16
16
  ALL_GIT_DIFF_CACHED_NAME_ONLY_NULL_TERMINATED_COMMAND,
17
17
  ALL_GIT_DIFF_NAME_ONLY_NULL_TERMINATED_COMMAND_PREFIX,
18
- ALL_LITERAL_KEYWORD_EXEMPTIONS,
19
18
  ALL_TEST_FILENAME_GLOB_SUFFIXES,
20
19
  ALL_TEST_FILENAME_SUFFIXES,
21
- COLUMN_KEY_PATTERN_TEMPLATE,
22
- CONFIG_PATH_SEGMENT,
23
20
  EXPECTED_NON_RENAME_COLUMN_COUNT,
24
21
  EXPECTED_RENAME_COLUMN_COUNT,
25
- EXPECTED_TUPLE_PAIR_LENGTH,
26
22
  GIT_NAME_STATUS_ADDED_PREFIX,
27
23
  GIT_NAME_STATUS_RENAMED_PREFIX,
28
24
  MAX_VIOLATIONS_PER_CHECK,
29
- MINIMUM_COLUMN_NAME_LENGTH_AFTER_FIRST_CHAR,
30
25
  PYTHON_FILE_EXTENSION,
31
26
  TEST_CONFTEST_FILENAME,
32
27
  TEST_FILENAME_PREFIX,
@@ -365,58 +360,6 @@ def is_test_path(file_path: str) -> bool:
365
360
  return False
366
361
 
367
362
 
368
- def check_database_column_string_magic(content: str, file_path: str) -> list[str]:
369
- """Flag string literals that look like database/HTTP column or key names inside function bodies.
370
-
371
- Triggers when a snake_case string literal appears as the first element of a
372
- two-element tuple inside a function body (the characteristic column-name/value
373
- pair pattern). Files under ``config/`` and test files are exempt.
374
- """
375
- normalized_path = file_path.replace("\\", "/")
376
- if CONFIG_PATH_SEGMENT in normalized_path:
377
- return []
378
- if is_test_path(normalized_path):
379
- return []
380
- try:
381
- tree = ast.parse(content)
382
- except SyntaxError:
383
- return []
384
- issues: list[str] = []
385
- column_key_pattern = re.compile(
386
- COLUMN_KEY_PATTERN_TEMPLATE.format(
387
- minimum_length=MINIMUM_COLUMN_NAME_LENGTH_AFTER_FIRST_CHAR
388
- )
389
- )
390
- seen_tuple_node_ids: set[int] = set()
391
- for each_node in ast.walk(tree):
392
- if not isinstance(each_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
393
- continue
394
- for each_child in ast.walk(each_node):
395
- if not isinstance(each_child, ast.Tuple):
396
- continue
397
- if id(each_child) in seen_tuple_node_ids:
398
- continue
399
- seen_tuple_node_ids.add(id(each_child))
400
- if len(each_child.elts) != EXPECTED_TUPLE_PAIR_LENGTH:
401
- continue
402
- first_element = each_child.elts[0]
403
- if not isinstance(first_element, ast.Constant):
404
- continue
405
- if not isinstance(first_element.value, str):
406
- continue
407
- literal_text = first_element.value
408
- if not column_key_pattern.match(literal_text):
409
- continue
410
- if literal_text in ALL_LITERAL_KEYWORD_EXEMPTIONS:
411
- continue
412
- issues.append(
413
- f"Line {first_element.lineno}: Column-name string magic {literal_text!r} - extract to config"
414
- )
415
- if len(issues) >= MAX_VIOLATIONS_PER_CHECK:
416
- return issues
417
- return issues
418
-
419
-
420
363
  def _iter_calls_excluding_nested_functions(node: ast.AST) -> Iterator[ast.Call]:
421
364
  for each_child in ast.iter_child_nodes(node):
422
365
  if isinstance(each_child, (ast.FunctionDef, ast.AsyncFunctionDef)):
@@ -826,9 +769,6 @@ def run_gate(
826
769
  repository_root.resolve(), relative_posix
827
770
  )
828
771
  issues = validate_content(content, relative_posix, prior_content)
829
- issues.extend(
830
- check_database_column_string_magic(content, relative_posix)
831
- )
832
772
  issues.extend(check_wrapper_plumb_through(content, relative_posix))
833
773
  if not issues:
834
774
  continue
@@ -0,0 +1,199 @@
1
+ """Constants for post_audit_thread.py.
2
+
3
+ Centralizes every literal the script and its tests need so the script body
4
+ contains no magic values beyond the integer literals exempt from
5
+ ``check_magic_values`` (``0``, ``1``, ``-1``). Constants live here per
6
+ CODE_RULES.md §4 (Config Locations) and §3 (Reuse Constants).
7
+
8
+ All scalar constants stay narrowly typed so the consuming script and tests
9
+ can rely on ``int`` / ``str`` / ``tuple`` semantics without runtime checks.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from pathlib import Path
15
+
16
+ SKILL_BUGTEAM: str = "bugteam"
17
+ SKILL_FINDBUGS: str = "findbugs"
18
+ SKILL_QBUG: str = "qbug"
19
+ ALL_SUPPORTED_SKILLS: tuple[str, ...] = (SKILL_BUGTEAM, SKILL_FINDBUGS, SKILL_QBUG)
20
+
21
+ STATE_CLEAN: str = "CLEAN"
22
+ STATE_DIRTY: str = "DIRTY"
23
+ ALL_SUPPORTED_STATES: tuple[str, ...] = (STATE_CLEAN, STATE_DIRTY)
24
+
25
+ SEVERITY_TAG_P0: str = "P0"
26
+ SEVERITY_TAG_P1: str = "P1"
27
+ SEVERITY_TAG_P2: str = "P2"
28
+ ALL_SUPPORTED_SEVERITY_TAGS: tuple[str, ...] = (
29
+ SEVERITY_TAG_P0,
30
+ SEVERITY_TAG_P1,
31
+ SEVERITY_TAG_P2,
32
+ )
33
+
34
+ INLINE_COMMENT_SIDE_RIGHT: str = "RIGHT"
35
+ INLINE_COMMENT_SIDE_LEFT: str = "LEFT"
36
+ ALL_SUPPORTED_INLINE_COMMENT_SIDES: tuple[str, ...] = (
37
+ INLINE_COMMENT_SIDE_RIGHT,
38
+ INLINE_COMMENT_SIDE_LEFT,
39
+ )
40
+
41
+ GITHUB_API_BASE_URL: str = "https://api.github.com"
42
+ GITHUB_API_USER_AGENT: str = "post_audit_thread.py/1"
43
+ GITHUB_API_ACCEPT_HEADER: str = "application/vnd.github+json"
44
+ GITHUB_API_VERSION_HEADER: str = "2022-11-28"
45
+
46
+ GITHUB_REVIEW_EVENT_APPROVE: str = "APPROVE"
47
+ GITHUB_REVIEW_EVENT_REQUEST_CHANGES: str = "REQUEST_CHANGES"
48
+
49
+ HTTP_STATUS_SUCCESS_RANGE_LOW: int = 200
50
+ HTTP_STATUS_SUCCESS_RANGE_HIGH: int = 300
51
+
52
+ HTTP_AUTHORIZATION_BEARER_PREFIX: str = "Bearer "
53
+ HTTP_HEADER_AUTHORIZATION: str = "Authorization"
54
+ HTTP_HEADER_ACCEPT: str = "Accept"
55
+ HTTP_HEADER_CONTENT_TYPE: str = "Content-Type"
56
+ HTTP_HEADER_GITHUB_API_VERSION: str = "X-GitHub-Api-Version"
57
+ HTTP_HEADER_USER_AGENT: str = "User-Agent"
58
+ HTTP_METHOD_POST: str = "POST"
59
+ HTTP_REQUEST_CONTENT_TYPE: str = "application/json"
60
+ HTTP_REQUEST_TIMEOUT_SECONDS: int = 30
61
+ ERROR_RESPONSE_PREVIEW_CHARS: int = 200
62
+
63
+ MAX_RETRY_ATTEMPTS: int = 3
64
+ ALL_RETRY_BACKOFF_SECONDS: tuple[int, ...] = (1, 4, 16)
65
+
66
+ EXIT_CODE_USER_ERROR: int = 1
67
+ EXIT_CODE_RETRY_EXHAUSTED: int = 2
68
+
69
+ SHORT_SHA_LENGTH: int = 7
70
+
71
+ ALL_GH_AUTH_TOKEN_COMMAND_PARTS: tuple[str, ...] = ("gh", "auth", "token")
72
+ ALL_GH_API_USER_COMMAND_PARTS: tuple[str, ...] = ("gh", "api", "user")
73
+ ALL_GH_AUTH_STATUS_COMMAND_PARTS: tuple[str, ...] = ("gh", "auth", "status")
74
+ ALL_GH_API_COMMAND_PARTS: tuple[str, ...] = ("gh", "api")
75
+ GH_AUTH_TOKEN_USER_FLAG: str = "--user"
76
+ GH_USER_LOGIN_FIELD: str = "login"
77
+ GH_PR_USER_FIELD: str = "user"
78
+ GH_API_PR_PATH_TEMPLATE: str = "repos/{owner}/{repo}/pulls/{pr_number}"
79
+ GH_AUTH_STATUS_ACCOUNT_LINE_MARKER: str = "Logged in to github.com account"
80
+ GH_AUTH_STATUS_ACCOUNT_LINE_TOKEN_SEPARATOR: str = " "
81
+
82
+ GH_TOKEN_ENV_VAR_NAME: str = "GH_TOKEN"
83
+ GITHUB_TOKEN_ENV_VAR_NAME: str = "GITHUB_TOKEN"
84
+ ALL_GH_TOKEN_ENV_VAR_NAMES: tuple[str, ...] = (
85
+ GH_TOKEN_ENV_VAR_NAME,
86
+ GITHUB_TOKEN_ENV_VAR_NAME,
87
+ )
88
+ BUGTEAM_REVIEWER_ACCOUNT_ENV_VAR_NAME: str = "BUGTEAM_REVIEWER_ACCOUNT"
89
+
90
+ JSON_FIELD_PATH: str = "path"
91
+ JSON_FIELD_LINE: str = "line"
92
+ JSON_FIELD_SIDE: str = "side"
93
+ JSON_FIELD_SEVERITY: str = "severity"
94
+ JSON_FIELD_DESCRIPTION: str = "description"
95
+ JSON_FIELD_FIX_SUMMARY: str = "fix_summary"
96
+ ALL_REQUIRED_FINDING_FIELDS: tuple[str, ...] = (
97
+ JSON_FIELD_PATH,
98
+ JSON_FIELD_LINE,
99
+ JSON_FIELD_SIDE,
100
+ JSON_FIELD_SEVERITY,
101
+ JSON_FIELD_DESCRIPTION,
102
+ JSON_FIELD_FIX_SUMMARY,
103
+ )
104
+
105
+ REVIEW_REQUEST_FIELD_COMMIT_ID: str = "commit_id"
106
+ REVIEW_REQUEST_FIELD_BODY: str = "body"
107
+ REVIEW_REQUEST_FIELD_EVENT: str = "event"
108
+ REVIEW_REQUEST_FIELD_COMMENTS: str = "comments"
109
+
110
+ REVIEW_RESPONSE_FIELD_HTML_URL: str = "html_url"
111
+
112
+ INLINE_COMMENT_FIELD_PATH: str = "path"
113
+ INLINE_COMMENT_FIELD_LINE: str = "line"
114
+ INLINE_COMMENT_FIELD_SIDE: str = "side"
115
+ INLINE_COMMENT_FIELD_BODY: str = "body"
116
+
117
+ AUDIT_REPLY_TEMPLATE_FILENAME: str = "audit-reply-template.md"
118
+ TEMPLATE_FENCE_TOKEN: str = "```"
119
+
120
+ PLACEHOLDER_SKILL: str = "<Skill>"
121
+ PLACEHOLDER_STATE_LABEL: str = "<state_label>"
122
+ PLACEHOLDER_HEADING: str = "<heading>"
123
+ PLACEHOLDER_SUMMARY_PARAGRAPH: str = "<summary paragraph>"
124
+ PLACEHOLDER_FINDINGS_COUNT: str = "<N>"
125
+ PLACEHOLDER_P0_COUNT: str = "<P0 count>"
126
+ PLACEHOLDER_P1_COUNT: str = "<P1 count>"
127
+ PLACEHOLDER_P2_COUNT: str = "<P2 count>"
128
+ PLACEHOLDER_DETAILS_BLOCK: str = "<optional collapsed details section per finding>"
129
+
130
+ STATE_LABEL_FOR_CLEAN: str = "Clean — no findings"
131
+ STATE_LABEL_FOR_DIRTY: str = "Findings requested"
132
+ HEADING_FOR_CLEAN: str = "Audit pass clean"
133
+ HEADING_FOR_DIRTY: str = "Findings recorded as inline review comments"
134
+
135
+ SUMMARY_PARAGRAPH_CLEAN_TEMPLATE: str = (
136
+ "The {skill_display} audit pass against commit `{short_commit}` found no "
137
+ "findings. No inline review comments were posted; the PR carries zero "
138
+ "unresolved threads originating from this audit pass."
139
+ )
140
+ SUMMARY_PARAGRAPH_DIRTY_TEMPLATE: str = (
141
+ "The {skill_display} audit pass against commit `{short_commit}` surfaced "
142
+ "{findings_count} finding(s). Each finding is posted below as an inline "
143
+ "review comment so it becomes its own resolvable thread; the unresolved-"
144
+ "thread gate picks them up at the next pr-converge step boundary."
145
+ )
146
+
147
+ DETAILS_BLOCK_HEADER: str = "<details>\n<summary>Finding details</summary>\n"
148
+ DETAILS_BLOCK_BULLET_TEMPLATE: str = (
149
+ "- **[{severity}]** `{path}:{line}` — {description}"
150
+ )
151
+ DETAILS_BLOCK_FOOTER: str = "\n</details>"
152
+
153
+ INLINE_COMMENT_BODY_TEMPLATE: str = (
154
+ "**[{severity}] {skill_display} audit finding**\n\n"
155
+ "{description}\n\n"
156
+ "**Suggested fix:** {fix_summary}"
157
+ )
158
+
159
+ CLI_FLAG_SKILL: str = "--skill"
160
+ CLI_FLAG_OWNER: str = "--owner"
161
+ CLI_FLAG_REPO: str = "--repo"
162
+ CLI_FLAG_PR_NUMBER: str = "--pr-number"
163
+ CLI_FLAG_COMMIT: str = "--commit"
164
+ CLI_FLAG_STATE: str = "--state"
165
+ CLI_FLAG_FINDINGS_JSON: str = "--findings-json"
166
+
167
+ REVIEWS_API_PATH_TEMPLATE: str = "/repos/{owner}/{repo}/pulls/{pr_number}/reviews"
168
+ SINGLE_REVIEW_API_PATH_TEMPLATE: str = (
169
+ "/repos/{owner}/{repo}/pulls/{pr_number}/reviews/{review_id}"
170
+ )
171
+ SINGLE_REVIEW_COMMENTS_API_PATH_TEMPLATE: str = (
172
+ "/repos/{owner}/{repo}/pulls/{pr_number}/reviews/{review_id}/comments"
173
+ )
174
+
175
+ AUDIT_BODY_SKELETON_OPEN_MARKER: str = "<!-- audit-body-skeleton:start -->"
176
+ AUDIT_BODY_SKELETON_CLOSE_MARKER: str = "<!-- audit-body-skeleton:end -->"
177
+
178
+
179
+ def script_directory() -> Path:
180
+ """Return the absolute path of the parent directory holding the consuming script.
181
+
182
+ Returns:
183
+ Path to ``_shared/pr-loop/scripts/`` resolved through this constants
184
+ module's location. Callers may walk up one further level
185
+ (``script_directory().parent``) to reach the
186
+ ``_shared/pr-loop/`` directory where ``audit-reply-template.md`` lives.
187
+ """
188
+ return Path(__file__).resolve().parent.parent
189
+
190
+
191
+ def template_path() -> Path:
192
+ """Return the absolute path to ``audit-reply-template.md``.
193
+
194
+ Returns:
195
+ Path object pointing to ``_shared/pr-loop/audit-reply-template.md``
196
+ relative to this constants module. Callers read this file at runtime
197
+ so the markdown doc remains the source of truth for the body skeleton.
198
+ """
199
+ return script_directory().parent / AUDIT_REPLY_TEMPLATE_FILENAME
@@ -0,0 +1,8 @@
1
+ """Configuration constants for the CLAUDE_REVIEWS_DISABLED opt-out gate."""
2
+
3
+ from __future__ import annotations
4
+
5
+ CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME: str = "CLAUDE_REVIEWS_DISABLED"
6
+ CLAUDE_REVIEWS_DISABLED_TOKEN_SEPARATOR: str = ","
7
+ CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN: str = "bugteam"
8
+ EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV: int = 7