claude-dev-env 2.12.0 → 2.14.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 (399) hide show
  1. package/AGENTS.md +61 -0
  2. package/CLAUDE.md +1 -57
  3. package/_shared/AGENTS.md +15 -0
  4. package/_shared/CLAUDE.md +1 -15
  5. package/_shared/advisor/AGENTS.md +22 -0
  6. package/_shared/advisor/CLAUDE.md +1 -22
  7. package/_shared/pr-loop/AGENTS.md +27 -0
  8. package/_shared/pr-loop/CLAUDE.md +1 -27
  9. package/_shared/pr-loop/scripts/AGENTS.md +35 -0
  10. package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
  11. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
  13. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
  14. package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
  15. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
  16. package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
  17. package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
  18. package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
  19. package/_shared/process-tree/AGENTS.md +41 -0
  20. package/_shared/process-tree/CLAUDE.md +1 -41
  21. package/agents/AGENTS.md +31 -0
  22. package/agents/CLAUDE.md +1 -32
  23. package/agents/clean-coder.md +6 -6
  24. package/agents/pr-description-writer.md +11 -81
  25. package/agents/test_agent_frontmatter.py +4 -4
  26. package/audit-rubrics/AGENTS.md +43 -0
  27. package/audit-rubrics/CLAUDE.md +1 -43
  28. package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
  29. package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
  30. package/audit-rubrics/prompts/AGENTS.md +37 -0
  31. package/audit-rubrics/prompts/CLAUDE.md +1 -37
  32. package/bin/AGENTS.md +112 -0
  33. package/bin/CLAUDE.md +1 -112
  34. package/bin/ever-shipped-skills.mjs +1 -0
  35. package/bin/install-constants.mjs +6 -7
  36. package/bin/install.mjs +71 -13
  37. package/bin/install.prune.test.mjs +26 -0
  38. package/bin/install.settings-defaults.test.mjs +60 -33
  39. package/bin/install.test.mjs +36 -4
  40. package/commands/AGENTS.md +23 -0
  41. package/commands/CLAUDE.md +1 -23
  42. package/commands/hook-log-extract.md +3 -3
  43. package/commands/sr-loop.md +9 -5
  44. package/docs/AGENTS.md +32 -0
  45. package/docs/CLAUDE.md +1 -33
  46. package/docs/CODE_RULES.md +1 -1
  47. package/docs/imagegen.md +22 -0
  48. package/docs/references/AGENTS.md +17 -0
  49. package/docs/references/CLAUDE.md +1 -18
  50. package/hooks/AGENTS.md +31 -0
  51. package/hooks/CLAUDE.md +1 -31
  52. package/hooks/_gh_pr_author_swap_utils.py +14 -0
  53. package/hooks/advisory/AGENTS.md +16 -0
  54. package/hooks/advisory/CLAUDE.md +1 -16
  55. package/hooks/blocking/AGENTS.md +123 -0
  56. package/hooks/blocking/CLAUDE.md +1 -148
  57. package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
  58. package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
  59. package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
  60. package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
  61. package/hooks/blocking/code_rules_probe_chains.py +6 -2
  62. package/hooks/blocking/config/AGENTS.md +10 -0
  63. package/hooks/blocking/config/CLAUDE.md +1 -22
  64. package/hooks/blocking/conventional_pr_title_gate.py +1 -2
  65. package/hooks/blocking/gh_pr_author_restore.py +7 -2
  66. package/hooks/blocking/intent_only_ending_blocker.py +11 -16
  67. package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
  68. package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
  69. package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
  70. package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
  71. package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
  72. package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
  73. package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
  74. package/hooks/blocking/stop_dispatcher.py +4 -4
  75. package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
  76. package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
  77. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
  78. package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
  79. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
  80. package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
  81. package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
  82. package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
  83. package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
  84. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
  85. package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
  86. package/hooks/diagnostic/AGENTS.md +43 -0
  87. package/hooks/diagnostic/CLAUDE.md +1 -43
  88. package/hooks/diagnostic/hook_log_extractor.py +4 -38
  89. package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
  90. package/hooks/diagnostic/migrations/AGENTS.md +16 -0
  91. package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
  92. package/hooks/diagnostic/queries/AGENTS.md +19 -0
  93. package/hooks/diagnostic/queries/CLAUDE.md +1 -19
  94. package/hooks/diagnostic/test_hook_log_extractor.py +10 -23
  95. package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
  96. package/hooks/git-hooks/AGENTS.md +31 -0
  97. package/hooks/git-hooks/CLAUDE.md +1 -31
  98. package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
  99. package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
  100. package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -12
  101. package/hooks/git-hooks/pre_push.py +49 -118
  102. package/hooks/git-hooks/test_pre_push.py +111 -137
  103. package/hooks/hooks.json +0 -35
  104. package/hooks/hooks_constants/AGENTS.md +104 -0
  105. package/hooks/hooks_constants/CLAUDE.md +1 -113
  106. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
  107. package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
  108. package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
  109. package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
  110. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
  111. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
  112. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
  113. package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
  114. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
  115. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
  116. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
  117. package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
  118. package/hooks/lifecycle/AGENTS.md +18 -0
  119. package/hooks/lifecycle/CLAUDE.md +1 -20
  120. package/hooks/observability/AGENTS.md +20 -0
  121. package/hooks/observability/CLAUDE.md +1 -20
  122. package/hooks/session/AGENTS.md +33 -0
  123. package/hooks/session/CLAUDE.md +1 -33
  124. package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
  125. package/hooks/session/task_list_loop_starter.py +3 -3
  126. package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
  127. package/hooks/session/test_task_list_loop_starter.py +10 -2
  128. package/hooks/session/test_working_style_prompt.py +9 -4
  129. package/hooks/validation/AGENTS.md +20 -0
  130. package/hooks/validation/CLAUDE.md +1 -20
  131. package/hooks/validators/AGENTS.md +51 -0
  132. package/hooks/validators/CLAUDE.md +1 -51
  133. package/hooks/validators/health_check.py +52 -19
  134. package/hooks/validators/python_style_checks.py +1 -1
  135. package/hooks/validators/test_health_check.py +112 -27
  136. package/hooks/workflow/AGENTS.md +16 -0
  137. package/hooks/workflow/CLAUDE.md +1 -16
  138. package/installable-surfaces.manifest.json +1 -0
  139. package/output-styles/AGENTS.md +15 -0
  140. package/output-styles/CLAUDE.md +1 -15
  141. package/package.json +2 -1
  142. package/rules/AGENTS.md +61 -0
  143. package/rules/CLAUDE.md +1 -63
  144. package/rules/code-standards.md +5 -9
  145. package/rules/doc-prose-cuts.md +1 -1
  146. package/rules/gh-cli-conventions.md +0 -1
  147. package/rules/git-workflow.md +1 -3
  148. package/scripts/AGENTS.md +62 -0
  149. package/scripts/CLAUDE.md +1 -63
  150. package/scripts/_code_review_test_support.py +0 -95
  151. package/scripts/codex_compat_materializer.py +4 -0
  152. package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
  153. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
  154. package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
  155. package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
  156. package/scripts/invoke_code_review.py +8 -451
  157. package/scripts/sync_to_cursor/AGENTS.md +23 -0
  158. package/scripts/sync_to_cursor/CLAUDE.md +1 -23
  159. package/scripts/test_invoke_code_review.py +5 -61
  160. package/scripts/test_invoke_code_review_cli.py +1 -45
  161. package/scripts/test_invoke_code_review_contract.py +1 -118
  162. package/scripts/test_validate_instruction_pairs.py +90 -0
  163. package/scripts/test_verify_installable_package.py +5 -1
  164. package/scripts/tests/AGENTS.md +33 -0
  165. package/scripts/tests/CLAUDE.md +1 -33
  166. package/scripts/tests/test_codex_compat_materializer.py +36 -1
  167. package/scripts/validate_instruction_pairs.py +183 -0
  168. package/settings.json +1 -10
  169. package/skills/AGENTS.md +72 -0
  170. package/skills/CLAUDE.md +1 -64
  171. package/skills/_shared/AGENTS.md +44 -0
  172. package/skills/_shared/CLAUDE.md +1 -44
  173. package/skills/_shared/advisor/AGENTS.md +9 -0
  174. package/skills/_shared/advisor/CLAUDE.md +1 -9
  175. package/skills/_shared/pr-loop/AGENTS.md +50 -0
  176. package/skills/_shared/pr-loop/CLAUDE.md +1 -50
  177. package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
  178. package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
  179. package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
  180. package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
  181. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
  182. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
  183. package/skills/anthropic-plan/AGENTS.md +34 -0
  184. package/skills/anthropic-plan/CLAUDE.md +1 -34
  185. package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
  186. package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
  187. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
  188. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
  189. package/skills/anthropic-plan/templates/AGENTS.md +13 -0
  190. package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
  191. package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
  192. package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
  193. package/skills/auditing-claude-config/AGENTS.md +21 -0
  194. package/skills/auditing-claude-config/CLAUDE.md +1 -21
  195. package/skills/autoconverge/AGENTS.md +36 -0
  196. package/skills/autoconverge/CLAUDE.md +1 -36
  197. package/skills/autoconverge/reference/AGENTS.md +16 -0
  198. package/skills/autoconverge/reference/CLAUDE.md +1 -16
  199. package/skills/autoconverge/reference/convergence.md +7 -7
  200. package/skills/autoconverge/reference/gotchas.md +3 -10
  201. package/skills/autoconverge/workflow/AGENTS.md +26 -0
  202. package/skills/autoconverge/workflow/CLAUDE.md +1 -26
  203. package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
  204. package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
  205. package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
  206. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
  207. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
  208. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
  209. package/skills/autoconverge/workflow/converge.mjs +201 -238
  210. package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
  211. package/skills/bugteam/AGENTS.md +30 -0
  212. package/skills/bugteam/CLAUDE.md +1 -30
  213. package/skills/bugteam/CONSTRAINTS.md +1 -1
  214. package/skills/bugteam/SKILL.md +9 -0
  215. package/skills/bugteam/reference/AGENTS.md +20 -0
  216. package/skills/bugteam/reference/CLAUDE.md +1 -20
  217. package/skills/bugteam/reference/audit-and-teammates.md +10 -6
  218. package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
  219. package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
  220. package/skills/bugteam/scripts/AGENTS.md +30 -0
  221. package/skills/bugteam/scripts/CLAUDE.md +1 -30
  222. package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
  223. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
  224. package/skills/bugteam/test_skill_additions.py +9 -0
  225. package/skills/closeout/reference/handoff-prompt-template.md +1 -1
  226. package/skills/codex-review/AGENTS.md +46 -0
  227. package/skills/codex-review/CLAUDE.md +1 -46
  228. package/skills/codex-review/reference/AGENTS.md +15 -0
  229. package/skills/codex-review/reference/CLAUDE.md +1 -15
  230. package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
  231. package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
  232. package/skills/codex-review/test_skill_scaffold.py +3 -3
  233. package/skills/comments/SKILL.md +65 -0
  234. package/skills/copilot-review/AGENTS.md +18 -0
  235. package/skills/copilot-review/CLAUDE.md +1 -18
  236. package/skills/descriptions/SKILL.md +51 -0
  237. package/skills/emergencies/SKILL.md +42 -0
  238. package/skills/everything-search/AGENTS.md +17 -0
  239. package/skills/everything-search/CLAUDE.md +1 -17
  240. package/skills/fresh-branch/AGENTS.md +14 -0
  241. package/skills/fresh-branch/CLAUDE.md +1 -14
  242. package/skills/grok-spawn/AGENTS.md +28 -0
  243. package/skills/grok-spawn/CLAUDE.md +1 -28
  244. package/skills/orchestrator/SKILL.md +2 -4
  245. package/skills/plan-to-pr/SKILL.md +6 -7
  246. package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
  247. package/skills/plan-to-pr/reference/process-inventory.md +2 -2
  248. package/skills/plan-to-pr/reference/review-loop.md +2 -2
  249. package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
  250. package/skills/plan-to-pr/reference/task-seeds.md +1 -1
  251. package/skills/plan-to-pr/reference/task-ticket.md +3 -4
  252. package/skills/plan-to-pr/scripts/config/constants.py +1 -2
  253. package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
  254. package/skills/plan-to-pr/test_skill_contract.py +2 -2
  255. package/skills/pr-converge/AGENTS.md +32 -0
  256. package/skills/pr-converge/CLAUDE.md +1 -32
  257. package/skills/pr-converge/SKILL.md +13 -16
  258. package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
  259. package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
  260. package/skills/pr-converge/reference/AGENTS.md +28 -0
  261. package/skills/pr-converge/reference/CLAUDE.md +1 -28
  262. package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
  263. package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
  264. package/skills/pr-converge/reference/progress-checklist.md +6 -5
  265. package/skills/pr-converge/reference/state-schema.md +1 -27
  266. package/skills/pr-converge/scripts/AGENTS.md +46 -0
  267. package/skills/pr-converge/scripts/CLAUDE.md +1 -46
  268. package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
  269. package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
  270. package/skills/pr-converge/workflows/AGENTS.md +16 -0
  271. package/skills/pr-converge/workflows/CLAUDE.md +1 -16
  272. package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
  273. package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
  274. package/skills/pr-loop-lifecycle/SKILL.md +1 -1
  275. package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
  276. package/skills/prototype/SKILL.md +4 -4
  277. package/skills/prototype/reference/honest-limitations.md +5 -5
  278. package/skills/prototype/reference/promotion-tasks.md +2 -2
  279. package/skills/prototype/workflows/promotion.md +4 -6
  280. package/skills/rebase/AGENTS.md +32 -0
  281. package/skills/rebase/CLAUDE.md +1 -32
  282. package/skills/recall/AGENTS.md +30 -0
  283. package/skills/recall/CLAUDE.md +1 -30
  284. package/skills/remember/AGENTS.md +31 -0
  285. package/skills/remember/CLAUDE.md +1 -31
  286. package/skills/reviews/SKILL.md +85 -0
  287. package/skills/session-log/AGENTS.md +32 -0
  288. package/skills/session-log/CLAUDE.md +1 -32
  289. package/skills/session-tidy/AGENTS.md +36 -0
  290. package/skills/session-tidy/CLAUDE.md +1 -36
  291. package/skills/skill-builder/AGENTS.md +49 -0
  292. package/skills/skill-builder/CLAUDE.md +1 -49
  293. package/skills/skill-builder/references/AGENTS.md +25 -0
  294. package/skills/skill-builder/references/CLAUDE.md +1 -25
  295. package/skills/skill-builder/references/deterministic-elements.md +1 -1
  296. package/skills/skill-builder/templates/AGENTS.md +14 -0
  297. package/skills/skill-builder/templates/CLAUDE.md +1 -14
  298. package/skills/skill-builder/workflows/AGENTS.md +19 -0
  299. package/skills/skill-builder/workflows/CLAUDE.md +1 -19
  300. package/skills/small-cl/SKILL.md +52 -0
  301. package/skills/task-build/AGENTS.md +29 -0
  302. package/skills/task-build/CLAUDE.md +1 -29
  303. package/skills/update/AGENTS.md +38 -0
  304. package/skills/update/CLAUDE.md +1 -38
  305. package/system-prompts/AGENTS.md +17 -0
  306. package/system-prompts/CLAUDE.md +1 -17
  307. package/system-prompts/software-engineer.xml +3 -3
  308. package/agents/code-verifier.md +0 -74
  309. package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
  310. package/docs/references/code-review-enforcement.md +0 -132
  311. package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
  312. package/hooks/blocking/code_review_gate_deny.py +0 -74
  313. package/hooks/blocking/code_review_pr_create_gate.py +0 -198
  314. package/hooks/blocking/code_review_push_gate.py +0 -145
  315. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
  316. package/hooks/blocking/code_review_stamp_store.py +0 -233
  317. package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
  318. package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
  319. package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
  320. package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
  321. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
  322. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
  323. package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
  324. package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
  325. package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
  326. package/hooks/blocking/config/verified_commit_constants.py +0 -160
  327. package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
  328. package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
  329. package/hooks/blocking/conftest.py +0 -123
  330. package/hooks/blocking/convergence_gate_blocker.py +0 -310
  331. package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
  332. package/hooks/blocking/pr_description_body_audit.py +0 -148
  333. package/hooks/blocking/pr_description_command_parser.py +0 -237
  334. package/hooks/blocking/pr_description_enforcer.py +0 -227
  335. package/hooks/blocking/pr_description_pr_number.py +0 -155
  336. package/hooks/blocking/pr_description_proof_of_work.py +0 -385
  337. package/hooks/blocking/pr_description_readability.py +0 -364
  338. package/hooks/blocking/reviewer_spawn_gate.py +0 -182
  339. package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
  340. package/hooks/blocking/test_code_review_gate_deny.py +0 -54
  341. package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
  342. package/hooks/blocking/test_code_review_push_gate.py +0 -205
  343. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
  344. package/hooks/blocking/test_code_review_stamp_store.py +0 -205
  345. package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
  346. package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
  347. package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
  348. package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
  349. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
  350. package/hooks/blocking/test_pr_description_enforcer.py +0 -221
  351. package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
  352. package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
  353. package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
  354. package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
  355. package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
  356. package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
  357. package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
  358. package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
  359. package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
  360. package/hooks/blocking/test_verification_verdict_store.py +0 -974
  361. package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
  362. package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
  363. package/hooks/blocking/test_verified_commit_gate.py +0 -581
  364. package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
  365. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
  366. package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
  367. package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
  368. package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
  369. package/hooks/blocking/verification_verdict_store.py +0 -1039
  370. package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
  371. package/hooks/blocking/verified_commit_gate.py +0 -113
  372. package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
  373. package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
  374. package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
  375. package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
  376. package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
  377. package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
  378. package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
  379. package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
  380. package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
  381. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
  382. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
  383. package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
  384. package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
  385. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
  386. package/hooks/blocking/verifier_verdict_minter.py +0 -280
  387. package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
  388. package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
  389. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
  390. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
  391. package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
  392. package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
  393. package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
  394. package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
  395. package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
  396. package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
  397. package/rules/proof-of-work-pr-comments.md +0 -22
  398. package/rules/verified-commit-gate-skip.md +0 -4
  399. package/scripts/Show-Asset.ps1 +0 -106
@@ -1,167 +0,0 @@
1
- """Configuration constants for the pr_description_enforcer PreToolUse hook."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
- import re
7
- from dataclasses import dataclass
8
- from pathlib import Path
9
-
10
-
11
- _PLUGIN_ROOT: str = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
- PR_GUIDE_PATH: str = os.path.join(_PLUGIN_ROOT, "docs", "PR_DESCRIPTION_GUIDE.md")
13
-
14
- MINIMUM_SUBSTANTIVE_PROSE_CHARS: int = 40
15
-
16
- FENCED_CODE_BLOCK_PATTERN: re.Pattern[str] = re.compile(r"```.*?```", re.DOTALL)
17
- INLINE_CODE_PATTERN: re.Pattern[str] = re.compile(r"`[^`]*`")
18
- HEADING_LINE_PATTERN: re.Pattern[str] = re.compile(r"^#+[ \t].*$", re.MULTILINE)
19
- BOLD_PAIR_PATTERN: re.Pattern[str] = re.compile(r"\*\*([^*]+?)\*\*")
20
- BULLET_MARKER_PATTERN: re.Pattern[str] = re.compile(r"^\s*[-*+]\s+", re.MULTILINE)
21
- BLOCKQUOTE_MARKER_PATTERN: re.Pattern[str] = re.compile(r"^\s*>\s+", re.MULTILINE)
22
- BLOCKQUOTE_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*>.*$", re.MULTILINE)
23
- TABLE_ROW_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*\|.*\|.*$", re.MULTILINE)
24
- LINK_TEXT_PATTERN: re.Pattern[str] = re.compile(r"\[([^\]]+)\]\([^)]+\)")
25
- WHITESPACE_RUN_PATTERN: re.Pattern[str] = re.compile(r"\s+")
26
- VAGUE_LANGUAGE_PATTERN: re.Pattern[str] = re.compile(
27
- r"\b(fix(?:ed)? (?:bug|issue|it)|update(?:d)? code|minor changes|various (?:fixes|updates|improvements))\b",
28
- re.IGNORECASE,
29
- )
30
-
31
- SUMMARY_HEADER: str = "## Summary"
32
- PROBLEM_HEADER: str = "## Problem"
33
- TEST_PLAN_HEADER: str = "## Test plan"
34
- TESTS_HEADER: str = "## Tests"
35
- TESTING_HEADER: str = "## Testing"
36
- VERIFICATION_HEADER: str = "## Verification"
37
- VALIDATION_HEADER: str = "## Validation"
38
-
39
- ALL_HEAVY_OPENING_HEADERS: frozenset[str] = frozenset({PROBLEM_HEADER, SUMMARY_HEADER})
40
- ALL_HEAVY_TESTING_HEADERS: frozenset[str] = frozenset(
41
- {TEST_PLAN_HEADER, TESTING_HEADER, TESTS_HEADER, VERIFICATION_HEADER, VALIDATION_HEADER}
42
- )
43
- GH_PR_COMMAND_MIN_TOKEN_COUNT: int = 3
44
- ALL_PR_NUMBER_BEARING_GH_PR_SUBCOMMANDS: frozenset[str] = frozenset({"edit", "comment", "ready"})
45
- BODY_FILE_STDIN_SENTINEL: str = "-"
46
- ATOMIC_WRITE_TEMP_SUFFIX: str = ".tmp"
47
- SELF_CLOSING_REFERENCE_MESSAGE_PREFIX: str = "PR body references its own PR number #"
48
- SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX: str = (
49
- " as a self-closing keyword (Fixes/Closes/Resolves) -- remove the self-reference"
50
- )
51
-
52
- SELF_REFERENCE_PATTERN_TEMPLATE: str = (
53
- r"\b(?:Close|Closes|Closed|Fix|Fixes|Fixed|Resolve|Resolves|Resolved)"
54
- r"\s+#{pr_number}\b"
55
- )
56
-
57
- THIS_PR_OPENING_PATTERN: re.Pattern[str] = re.compile(
58
- r"^\s*(?:#[^\n]*\n\s*)*This PR\b",
59
- re.IGNORECASE,
60
- )
61
-
62
- TRIVIAL_SHAPE: str = "trivial"
63
- STANDARD_SHAPE: str = "standard"
64
- HEAVY_SHAPE: str = "heavy"
65
-
66
- TRIVIAL_BODY_CHAR_THRESHOLD: int = 200
67
- HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION: int = 500
68
-
69
- READABILITY_MAX_SENTENCE_WORDS: int = 28
70
- READABILITY_AVG_SENTENCE_WORDS: int = 18
71
- READABILITY_MIN_FLESCH: int = 50
72
- READABILITY_STRIKE_THRESHOLD: int = 3
73
-
74
- READABILITY_LOOSEN_CAP: int = 3
75
- READABILITY_MIN_FLESCH_FLOOR: int = 30
76
- READABILITY_MAX_SENTENCE_WORDS_CEILING: int = 60
77
- READABILITY_AVG_SENTENCE_WORDS_CEILING: int = 40
78
-
79
- READABILITY_FLESCH_LOOSEN_FACTOR: float = 0.9
80
- READABILITY_SENTENCE_WORDS_LOOSEN_FACTOR: float = 10 / 9
81
-
82
- ALL_READABILITY_CLI_FLAG_TOKENS: frozenset[str] = frozenset(
83
- {
84
- "--readability-loosen",
85
- "--readability-reset",
86
- "--readability-disable",
87
- "--readability-enable",
88
- }
89
- )
90
-
91
- FLESCH_BASE_SCORE: float = 206.835
92
- FLESCH_WORDS_PER_SENTENCE_COEFFICIENT: float = 1.015
93
- FLESCH_SYLLABLES_PER_WORD_COEFFICIENT: float = 84.6
94
- FLESCH_PERFECT_SCORE: float = 100.0
95
-
96
- READABILITY_STATE_FILE: Path = Path.home() / ".claude" / "state" / "pr_description_readability_strikes.json"
97
- READABILITY_THRESHOLD_OVERRIDE_FILE: Path = (
98
- Path.home() / ".claude" / "state" / "pr_description_readability_overrides.json"
99
- )
100
- READABILITY_ENABLED_STATE_FILE: Path = (
101
- Path.home() / ".claude" / "state" / "pr_description_readability_enabled.json"
102
- )
103
-
104
-
105
- @dataclass(frozen=True)
106
- class ReadabilityThresholds:
107
- """Three readability thresholds carried as a single typed structure."""
108
-
109
- flesch_min: int
110
- max_sentence_words: int
111
- avg_sentence_words: int
112
-
113
-
114
- DEFAULT_READABILITY_THRESHOLDS: ReadabilityThresholds = ReadabilityThresholds(
115
- flesch_min=READABILITY_MIN_FLESCH,
116
- max_sentence_words=READABILITY_MAX_SENTENCE_WORDS,
117
- avg_sentence_words=READABILITY_AVG_SENTENCE_WORDS,
118
- )
119
-
120
-
121
- __all__ = [
122
- "ALL_HEAVY_OPENING_HEADERS",
123
- "ALL_HEAVY_TESTING_HEADERS",
124
- "ALL_PR_NUMBER_BEARING_GH_PR_SUBCOMMANDS",
125
- "ALL_READABILITY_CLI_FLAG_TOKENS",
126
- "ATOMIC_WRITE_TEMP_SUFFIX",
127
- "BLOCKQUOTE_LINE_PATTERN",
128
- "BLOCKQUOTE_MARKER_PATTERN",
129
- "BODY_FILE_STDIN_SENTINEL",
130
- "BOLD_PAIR_PATTERN",
131
- "BULLET_MARKER_PATTERN",
132
- "DEFAULT_READABILITY_THRESHOLDS",
133
- "FENCED_CODE_BLOCK_PATTERN",
134
- "FLESCH_BASE_SCORE",
135
- "FLESCH_PERFECT_SCORE",
136
- "FLESCH_SYLLABLES_PER_WORD_COEFFICIENT",
137
- "FLESCH_WORDS_PER_SENTENCE_COEFFICIENT",
138
- "GH_PR_COMMAND_MIN_TOKEN_COUNT",
139
- "HEADING_LINE_PATTERN",
140
- "HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION",
141
- "HEAVY_SHAPE",
142
- "INLINE_CODE_PATTERN",
143
- "LINK_TEXT_PATTERN",
144
- "MINIMUM_SUBSTANTIVE_PROSE_CHARS",
145
- "PR_GUIDE_PATH",
146
- "READABILITY_AVG_SENTENCE_WORDS_CEILING",
147
- "READABILITY_ENABLED_STATE_FILE",
148
- "READABILITY_FLESCH_LOOSEN_FACTOR",
149
- "READABILITY_LOOSEN_CAP",
150
- "READABILITY_MAX_SENTENCE_WORDS_CEILING",
151
- "READABILITY_MIN_FLESCH_FLOOR",
152
- "READABILITY_SENTENCE_WORDS_LOOSEN_FACTOR",
153
- "READABILITY_STATE_FILE",
154
- "READABILITY_STRIKE_THRESHOLD",
155
- "READABILITY_THRESHOLD_OVERRIDE_FILE",
156
- "ReadabilityThresholds",
157
- "SELF_CLOSING_REFERENCE_MESSAGE_PREFIX",
158
- "SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX",
159
- "SELF_REFERENCE_PATTERN_TEMPLATE",
160
- "STANDARD_SHAPE",
161
- "TABLE_ROW_LINE_PATTERN",
162
- "THIS_PR_OPENING_PATTERN",
163
- "TRIVIAL_BODY_CHAR_THRESHOLD",
164
- "TRIVIAL_SHAPE",
165
- "VAGUE_LANGUAGE_PATTERN",
166
- "WHITESPACE_RUN_PATTERN",
167
- ]
@@ -1,107 +0,0 @@
1
- """Configuration constants for the proof-of-work PR-comment audit.
2
-
3
- Holds the proof-part detection patterns, the gap and linkage word lists,
4
- the gh command tokens the audit runs to read a PR's comments and diff, and
5
- the corrective messages returned when a proof part is missing or when
6
- ``gh pr ready`` runs with no passing proof comment on the PR.
7
- """
8
-
9
- from __future__ import annotations
10
-
11
- import re
12
-
13
- ALL_PROOF_HEADING_KEYWORDS: tuple[str, ...] = ("proof", "verification")
14
-
15
- PR_READY_INVOCATION_PATTERN: re.Pattern[str] = re.compile(r"(?:^|[;&|])\s*gh\s+pr\s+ready\b")
16
- PR_READY_UNDO_FLAG: str = "--undo"
17
-
18
- GH_EXECUTABLE: str = "gh"
19
- GH_API_SUBCOMMAND: str = "api"
20
- GH_PAGINATE_FLAG: str = "--paginate"
21
- GH_SLURP_FLAG: str = "--slurp"
22
- PR_COMMENTS_API_PATH_TEMPLATE: str = "repos/{{owner}}/{{repo}}/issues/{pr_number}/comments"
23
- ALL_PR_DIFF_SUBCOMMANDS: tuple[str, ...] = ("pr", "diff")
24
- PR_DIFF_NAME_ONLY_FLAG: str = "--name-only"
25
- COMMENT_BODY_JSON_FIELD: str = "body"
26
- GH_COMMAND_TIMEOUT_SECONDS: int = 6
27
- MAX_DIFF_SCAN_CHARS: int = 200000
28
-
29
- ALL_VISUAL_FILE_SUFFIXES: frozenset[str] = frozenset(
30
- {".png", ".jpg", ".jpeg", ".gif", ".webp", ".avif", ".svg", ".ico", ".html", ".css"}
31
- )
32
- HEX_COLOR_ADDED_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\+.*#[0-9A-Fa-f]{6}\b", re.MULTILINE)
33
- IMAGE_EMBED_PATTERN: re.Pattern[str] = re.compile(r"!\[[^\]]*\]\([^)\s]+\)")
34
- ISSUE_REFERENCE_PATTERN: re.Pattern[str] = re.compile(r"#\d+")
35
- PLAN_LINKAGE_KEYWORD_PATTERN: re.Pattern[str] = re.compile(
36
- r"\b(?:issue|phase|plan|parent|advanc\w*|milestone|part of)\b", re.IGNORECASE
37
- )
38
- DIGIT_PATTERN: re.Pattern[str] = re.compile(r"\d")
39
- ALL_HONEST_GAP_PHRASES: tuple[str, ...] = (
40
- "gap",
41
- "limitation",
42
- "cannot",
43
- "does not show",
44
- "not shown",
45
- "unverified",
46
- "not covered",
47
- )
48
-
49
- PROOF_PART_COMMAND_MESSAGE: str = (
50
- "proof comment missing a fenced command block showing the exact command(s) run on real data"
51
- )
52
- PROOF_PART_MEASURED_MESSAGE: str = (
53
- "proof comment missing a measured-value element -- add a table row or bullet fact carrying "
54
- "the numbers read from the produced artifact"
55
- )
56
- PROOF_PART_PLAN_LINKAGE_MESSAGE: str = (
57
- "proof comment missing a plan-linkage sentence -- add one line naming the parent issue or "
58
- "phase this PR advances, with its #number"
59
- )
60
- PROOF_PART_VISUAL_MESSAGE: str = (
61
- "proof comment missing a visual element on a visual change -- embed an image (color "
62
- "swatches, before/after screenshots) for values a human cannot read at a glance"
63
- )
64
- PROOF_PART_HONEST_GAPS_MESSAGE: str = (
65
- "proof comment missing an honest-gaps statement -- say plainly what this offline proof "
66
- "cannot show and what covers that gap"
67
- )
68
-
69
- PR_READY_GATE_MESSAGE_TEMPLATE: str = (
70
- "BLOCKED: [PROOF_OF_WORK] PR #{pr_number} carries no passing proof-of-work comment. "
71
- "Post one comment with a proof or verification heading carrying: "
72
- "(1) the exact command(s) run on real data in a fenced code block, "
73
- "(2) measured outcomes from the produced artifact as a table row or bullet facts, "
74
- "(3) one sentence naming the parent issue or phase this PR advances, with its #number, "
75
- "(4) an image embed when the diff touches images, HTML, CSS, or hex color values, and "
76
- "(5) an honest statement of what the offline proof cannot show. "
77
- "Then re-run gh pr ready."
78
- )
79
-
80
- __all__ = [
81
- "ALL_HONEST_GAP_PHRASES",
82
- "ALL_PROOF_HEADING_KEYWORDS",
83
- "ALL_PR_DIFF_SUBCOMMANDS",
84
- "ALL_VISUAL_FILE_SUFFIXES",
85
- "COMMENT_BODY_JSON_FIELD",
86
- "DIGIT_PATTERN",
87
- "GH_API_SUBCOMMAND",
88
- "GH_COMMAND_TIMEOUT_SECONDS",
89
- "GH_EXECUTABLE",
90
- "GH_PAGINATE_FLAG",
91
- "GH_SLURP_FLAG",
92
- "HEX_COLOR_ADDED_LINE_PATTERN",
93
- "IMAGE_EMBED_PATTERN",
94
- "ISSUE_REFERENCE_PATTERN",
95
- "MAX_DIFF_SCAN_CHARS",
96
- "PLAN_LINKAGE_KEYWORD_PATTERN",
97
- "PROOF_PART_COMMAND_MESSAGE",
98
- "PROOF_PART_HONEST_GAPS_MESSAGE",
99
- "PROOF_PART_MEASURED_MESSAGE",
100
- "PROOF_PART_PLAN_LINKAGE_MESSAGE",
101
- "PROOF_PART_VISUAL_MESSAGE",
102
- "PR_COMMENTS_API_PATH_TEMPLATE",
103
- "PR_DIFF_NAME_ONLY_FLAG",
104
- "PR_READY_GATE_MESSAGE_TEMPLATE",
105
- "PR_READY_INVOCATION_PATTERN",
106
- "PR_READY_UNDO_FLAG",
107
- ]
@@ -1,41 +0,0 @@
1
- """Configuration constants for the reviewer_spawn_gate PreToolUse hook."""
2
-
3
- from __future__ import annotations
4
-
5
- import re
6
- from pathlib import Path
7
-
8
- BASH_TOOL_NAME: str = "Bash"
9
-
10
- GATE_SENTINEL_MARKER: str = "CLAUDE_REVIEWER_GATE=autoconverge"
11
-
12
- COPILOT_REVIEWER_TOKEN: str = "copilot"
13
- BUGBOT_REVIEWER_TOKEN: str = "bugbot"
14
-
15
- COPILOT_REVIEWER_LABEL: str = "GitHub Copilot"
16
- BUGBOT_REVIEWER_LABEL: str = "Cursor Bugbot"
17
-
18
- ALL_COPILOT_TRIGGER_MARKERS: tuple[str, ...] = (
19
- "requested_reviewers",
20
- "copilot-pull-request-reviewer[bot]",
21
- )
22
-
23
- BUGBOT_TRIGGER_SCRIPT_MARKER: str = "post_fix_reply.py"
24
- BUGBOT_RUN_BODY_PATTERN: re.Pattern[str] = re.compile(
25
- r'--body\s+["\']bugbot run["\']', re.IGNORECASE
26
- )
27
-
28
- AVAILABILITY_SCRIPT_RELATIVE_PATH: Path = (
29
- Path("_shared") / "pr-loop" / "scripts" / "reviewer_availability.py"
30
- )
31
- AVAILABILITY_SCRIPT_PATH_ENV_VAR_NAME: str = "REVIEWER_SPAWN_GATE_AVAILABILITY_SCRIPT_PATH"
32
- AVAILABILITY_SCRIPT_TIMEOUT_SECONDS: int = 15
33
- AVAILABILITY_REVIEWER_FLAG: str = "--reviewer"
34
- AVAILABILITY_DOWN_EXIT_CODE: int = 3
35
-
36
- DENY_REASON_TEMPLATE: str = (
37
- "BLOCKED [reviewer-spawn-gate]: {reviewer_label} is down or out of quota "
38
- "this run. Skip requesting {reviewer_label} on this trigger — "
39
- "autoconverge requests it again once the availability check reports it "
40
- "back.\n\nAvailability check output: {availability_detail}"
41
- )
@@ -1,292 +0,0 @@
1
- """Behavior tests for pr_description_enforcer_constants module."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
- import sys
7
- from pathlib import Path
8
-
9
- import pytest
10
-
11
- _HOOKS_ROOT = Path(__file__).resolve().parent.parent
12
- if str(_HOOKS_ROOT) not in sys.path:
13
- sys.path.insert(0, str(_HOOKS_ROOT))
14
-
15
- from hooks_constants import pr_description_enforcer_constants as constants_module
16
-
17
-
18
- def test_plugin_root_is_private_module_attribute() -> None:
19
- assert hasattr(constants_module, "_PLUGIN_ROOT")
20
- assert isinstance(constants_module._PLUGIN_ROOT, str)
21
- assert os.path.isabs(constants_module._PLUGIN_ROOT)
22
-
23
-
24
- def test_plugin_root_public_name_is_not_exported() -> None:
25
- assert not hasattr(constants_module, "PLUGIN_ROOT")
26
-
27
-
28
- def test_pr_guide_path_resolves_under_plugin_root_docs() -> None:
29
- expected_pr_guide_path = os.path.join(
30
- constants_module._PLUGIN_ROOT, "docs", "PR_DESCRIPTION_GUIDE.md"
31
- )
32
- assert constants_module.PR_GUIDE_PATH == expected_pr_guide_path
33
-
34
-
35
- def test_fenced_code_block_pattern_matches_triple_backtick_block() -> None:
36
- sample_markdown = "before ```python\ncode\n``` after"
37
- match = constants_module.FENCED_CODE_BLOCK_PATTERN.search(sample_markdown)
38
- assert match is not None
39
- assert match.group(0).startswith("```")
40
- assert match.group(0).endswith("```")
41
-
42
-
43
- def test_inline_code_pattern_matches_single_backtick_span() -> None:
44
- match = constants_module.INLINE_CODE_PATTERN.search("see `value` here")
45
- assert match is not None
46
- assert match.group(0) == "`value`"
47
-
48
-
49
- def test_heading_line_pattern_matches_atx_heading() -> None:
50
- match = constants_module.HEADING_LINE_PATTERN.search("## Description\n")
51
- assert match is not None
52
- assert match.group(0).strip() == "## Description"
53
-
54
-
55
- def test_bold_pair_pattern_captures_inner_text() -> None:
56
- match = constants_module.BOLD_PAIR_PATTERN.search("this is **bold** text")
57
- assert match is not None
58
- assert match.group(1) == "bold"
59
-
60
-
61
- def test_bullet_marker_pattern_strips_dash_bullet_from_line() -> None:
62
- stripped_line = constants_module.BULLET_MARKER_PATTERN.sub("", "- first item")
63
- assert stripped_line == "first item"
64
-
65
-
66
- def test_blockquote_marker_pattern_strips_quote_marker_from_line() -> None:
67
- stripped_line = constants_module.BLOCKQUOTE_MARKER_PATTERN.sub("", "> quoted line")
68
- assert stripped_line == "quoted line"
69
-
70
-
71
- def test_link_text_pattern_captures_anchor_text() -> None:
72
- match = constants_module.LINK_TEXT_PATTERN.search("See [the docs](https://example.com) now")
73
- assert match is not None
74
- assert match.group(1) == "the docs"
75
-
76
-
77
- def test_whitespace_run_pattern_collapses_multiple_spaces() -> None:
78
- collapsed_text = constants_module.WHITESPACE_RUN_PATTERN.sub(" ", "a b\t\tc\n\nd")
79
- assert collapsed_text == "a b c d"
80
-
81
-
82
- def test_this_pr_opening_pattern_matches_any_verb() -> None:
83
- """The guide says any `This PR ...` opening is a hard block. The pattern
84
- must match regardless of the verb that follows, not a short allowlist."""
85
- test_inputs = [
86
- "This PR introduces a new feature.",
87
- "This PR improves the algorithm.",
88
- "This PR enables the cache.",
89
- "This PR documents the contract.",
90
- "This PR adds a check.",
91
- "This PR fixes the bug.",
92
- ]
93
- for each_input in test_inputs:
94
- assert constants_module.THIS_PR_OPENING_PATTERN.match(each_input), (
95
- f"`{each_input}` must match THIS_PR_OPENING_PATTERN regardless of verb"
96
- )
97
-
98
-
99
- def test_this_pr_opening_pattern_does_not_match_within_prose() -> None:
100
- """The block applies to body openings, not mid-paragraph mentions."""
101
- text_with_mid_mention = "Adds caching. This PR follows the playbook."
102
- assert constants_module.THIS_PR_OPENING_PATTERN.match(text_with_mid_mention) is None
103
-
104
-
105
- def test_all_list_is_alphabetically_sorted() -> None:
106
- """`__all__` is the export surface; alphabetical order makes it easy to
107
- verify completeness, spot duplicates, and bisect missing entries. Pin
108
- sorted order so drift cannot reintroduce the H-before-G / appended-at-end
109
- inconsistencies Bugbot flagged."""
110
- actual_all_list = constants_module.__all__
111
- expected_sorted = sorted(actual_all_list)
112
- if actual_all_list != expected_sorted:
113
- first_divergence_index = next(
114
- each_index
115
- for each_index, (each_actual_value, each_expected_value) in enumerate(zip(actual_all_list, expected_sorted))
116
- if each_actual_value != each_expected_value
117
- )
118
- raise AssertionError(
119
- "constants_module.__all__ must be alphabetically sorted; "
120
- f"the first divergence is at index {first_divergence_index}: "
121
- f"got {actual_all_list[first_divergence_index]!r}, "
122
- f"expected {expected_sorted[first_divergence_index]!r}"
123
- )
124
-
125
-
126
- def test_dead_heavy_detection_constants_are_removed() -> None:
127
- """`ALL_HEAVY_DETECTION_HEADERS` and `HEAVY_DETECTION_HEADER_COUNT_MIN`
128
- were remnants of the prior two-condition shape classifier (length AND
129
- detection-header count). e137dee9 simplified the classifier to use length
130
- alone, leaving both names as dead exports. Pin their removal so they
131
- cannot drift back as misleading vestigial constants."""
132
- for each_name in ("ALL_HEAVY_DETECTION_HEADERS", "HEAVY_DETECTION_HEADER_COUNT_MIN"):
133
- assert not hasattr(constants_module, each_name), (
134
- f"{each_name} must be deleted; the classifier now uses "
135
- "HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION alone."
136
- )
137
- assert each_name not in constants_module.__all__
138
-
139
-
140
- def test_self_closing_reference_message_prefix_and_suffix_compose_full_message() -> None:
141
- pr_number = 42
142
- composed_message = (
143
- f"{constants_module.SELF_CLOSING_REFERENCE_MESSAGE_PREFIX}"
144
- f"{pr_number}"
145
- f"{constants_module.SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX}"
146
- )
147
- assert "#42" in composed_message
148
- assert "Fixes/Closes/Resolves" in composed_message
149
- assert "self-reference" in composed_message
150
-
151
-
152
- def test_loosen_factors_are_inverse_paired() -> None:
153
- flesch_factor = constants_module.READABILITY_FLESCH_LOOSEN_FACTOR
154
- sentence_factor = constants_module.READABILITY_SENTENCE_WORDS_LOOSEN_FACTOR
155
- assert flesch_factor * sentence_factor == pytest.approx(1.0)
156
-
157
-
158
- def test_unused_header_constants_are_removed_from_module() -> None:
159
- """The four header constants FIX_HEADER, CHANGES_HEADER, APPROACH_HEADER,
160
- and ROOT_CAUSE_HEADER were dead exports with no call sites and must not be
161
- re-introduced as either module attributes or __all__ entries."""
162
- for each_dead_name in ("FIX_HEADER", "CHANGES_HEADER", "APPROACH_HEADER", "ROOT_CAUSE_HEADER"):
163
- assert not hasattr(constants_module, each_dead_name), (
164
- f"{each_dead_name} was re-introduced; the four header constants "
165
- "had zero call sites and were deleted."
166
- )
167
- assert each_dead_name not in constants_module.__all__, (
168
- f"{each_dead_name} re-appeared in __all__ even though it has no consumers."
169
- )
170
-
171
-
172
- def test_module_internal_header_constants_are_not_publicly_exported() -> None:
173
- """The seven header-name constants and three default-readability-threshold scalars
174
- are consumed only inside this same module (used to build ALL_HEAVY_* frozensets
175
- and DEFAULT_READABILITY_THRESHOLDS). They must remain module attributes for the
176
- builder expressions, but they must NOT appear in __all__ -- callers should import
177
- the public aggregates (ALL_HEAVY_OPENING_HEADERS / ALL_HEAVY_TESTING_HEADERS /
178
- DEFAULT_READABILITY_THRESHOLDS) instead of the individual scalars."""
179
- all_internal_only_names = (
180
- "SUMMARY_HEADER",
181
- "PROBLEM_HEADER",
182
- "TEST_PLAN_HEADER",
183
- "TESTS_HEADER",
184
- "TESTING_HEADER",
185
- "VERIFICATION_HEADER",
186
- "VALIDATION_HEADER",
187
- "READABILITY_MAX_SENTENCE_WORDS",
188
- "READABILITY_AVG_SENTENCE_WORDS",
189
- "READABILITY_MIN_FLESCH",
190
- )
191
- for each_internal_name in all_internal_only_names:
192
- assert hasattr(constants_module, each_internal_name), (
193
- f"{each_internal_name} must remain as a module attribute -- "
194
- "the aggregate builders reference it."
195
- )
196
- assert each_internal_name not in constants_module.__all__, (
197
- f"{each_internal_name} is consumed only inside the module and "
198
- "must not be advertised in __all__."
199
- )
200
-
201
-
202
- def test_self_reference_pattern_covers_all_nine_github_closing_keywords() -> None:
203
- """GitHub recognizes nine closing keywords: close/closes/closed,
204
- fix/fixes/fixed, resolve/resolves/resolved. The self-reference template
205
- must enumerate all nine so no variant bypasses the self-closing block."""
206
- pattern_source = constants_module.SELF_REFERENCE_PATTERN_TEMPLATE
207
- for each_keyword in (
208
- "Close", "Closes", "Closed",
209
- "Fix", "Fixes", "Fixed",
210
- "Resolve", "Resolves", "Resolved",
211
- ):
212
- assert each_keyword in pattern_source, (
213
- f"SELF_REFERENCE_PATTERN_TEMPLATE must enumerate `{each_keyword}` "
214
- f"to catch every GitHub closing-keyword variant; got: {pattern_source!r}"
215
- )
216
-
217
-
218
- def test_body_shape_string_literals_are_named_constants() -> None:
219
- """The three PR-body shape names (`trivial`, `standard`, `heavy`) are used
220
- by both `_compute_pr_body_shape` (return values) and `validate_pr_body`
221
- (string comparisons). Bugbot flagged the inline literals as cross-function
222
- magic strings. Pin the canonical names in `hooks_constants/` so a typo in
223
- either site cannot silently misclassify shape."""
224
- assert constants_module.TRIVIAL_SHAPE == "trivial"
225
- assert constants_module.STANDARD_SHAPE == "standard"
226
- assert constants_module.HEAVY_SHAPE == "heavy"
227
- for each_name in ("TRIVIAL_SHAPE", "STANDARD_SHAPE", "HEAVY_SHAPE"):
228
- assert each_name in constants_module.__all__
229
-
230
-
231
- def test_readability_cli_flag_tokens_exposes_four_flags() -> None:
232
- """ALL_READABILITY_CLI_FLAG_TOKENS centralises the four CLI flags the
233
- dispatcher recognises (loosen/reset/disable/enable). Pinning the set keeps
234
- main()'s dispatcher loop and the dispatcher itself in sync; adding a flag
235
- requires updating both the constant and the dispatcher in the same commit."""
236
- expected_tokens = frozenset(
237
- {
238
- "--readability-loosen",
239
- "--readability-reset",
240
- "--readability-disable",
241
- "--readability-enable",
242
- }
243
- )
244
- assert constants_module.ALL_READABILITY_CLI_FLAG_TOKENS == expected_tokens
245
- assert "ALL_READABILITY_CLI_FLAG_TOKENS" in constants_module.__all__
246
-
247
-
248
- def test_ceremony_header_pattern_is_removed() -> None:
249
- """`CEREMONY_HEADER_PATTERN` is replaced by the broader `HEADING_LINE_PATTERN`
250
- check in the Trivial-ceremony violation; the constant must not linger as a
251
- dead export to drift back into use."""
252
- assert not hasattr(constants_module, "CEREMONY_HEADER_PATTERN"), (
253
- "CEREMONY_HEADER_PATTERN must be deleted; the ceremony-on-Trivial check "
254
- "now uses HEADING_LINE_PATTERN to cover every heading level."
255
- )
256
- assert "CEREMONY_HEADER_PATTERN" not in constants_module.__all__
257
-
258
-
259
- def test_flesch_formula_coefficients_are_named_constants() -> None:
260
- """The Flesch Reading Ease formula coefficients (206.835, 1.015, 84.6) and
261
- the perfect-score default (100.0) must live as named UPPER_SNAKE constants
262
- in `hooks_constants/pr_description_enforcer_constants.py` so the production
263
- function body has zero magic numeric literals."""
264
- assert constants_module.FLESCH_BASE_SCORE == 206.835
265
- assert constants_module.FLESCH_WORDS_PER_SENTENCE_COEFFICIENT == 1.015
266
- assert constants_module.FLESCH_SYLLABLES_PER_WORD_COEFFICIENT == 84.6
267
- assert constants_module.FLESCH_PERFECT_SCORE == 100.0
268
- for each_name in (
269
- "FLESCH_BASE_SCORE",
270
- "FLESCH_WORDS_PER_SENTENCE_COEFFICIENT",
271
- "FLESCH_SYLLABLES_PER_WORD_COEFFICIENT",
272
- "FLESCH_PERFECT_SCORE",
273
- ):
274
- assert each_name in constants_module.__all__, (
275
- f"{each_name} must appear in __all__ so the enforcer can import it."
276
- )
277
-
278
-
279
- def test_all_heavy_testing_headers_enumerates_five_canonical_forms() -> None:
280
- """The frozenset ALL_HEAVY_TESTING_HEADERS drives the violation message that
281
- tells the writer which headers satisfy the heavy-shape testing-category
282
- requirement. The set must include all five canonical forms (Test plan,
283
- Testing, Tests, Verification, Validation) so the writer's documented
284
- vocabulary matches the message it receives on a violation."""
285
- expected_canonical_headers = [
286
- "## Test plan",
287
- "## Testing",
288
- "## Tests",
289
- "## Validation",
290
- "## Verification",
291
- ]
292
- assert sorted(constants_module.ALL_HEAVY_TESTING_HEADERS) == expected_canonical_headers