claude-dev-env 2.4.0 → 2.5.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 (195) hide show
  1. package/CLAUDE.md +53 -49
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +4 -2
  4. package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
  6. package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
  7. package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
  8. package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
  9. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
  10. package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
  12. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
  13. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
  14. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
  15. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
  16. package/_shared/pr-loop/worker-spawn.md +1 -1
  17. package/agents/CLAUDE.md +2 -1
  18. package/agents/caveman.md +0 -1
  19. package/agents/clasp-deployment-orchestrator.md +0 -1
  20. package/agents/clean-coder.md +0 -1
  21. package/agents/code-advisor.md +0 -1
  22. package/agents/code-quality-agent.md +1 -2
  23. package/agents/code-verifier.md +0 -1
  24. package/agents/deep-research.md +0 -1
  25. package/agents/docs-agent.md +0 -1
  26. package/agents/git-commit-crafter.md +0 -1
  27. package/agents/issue-tracker.md +42 -0
  28. package/agents/plan-packet-validator.md +0 -1
  29. package/agents/pr-description-writer.md +0 -1
  30. package/agents/test_agent_frontmatter.py +67 -18
  31. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
  32. package/bin/CLAUDE.md +68 -5
  33. package/bin/ever-shipped-skills.mjs +1 -0
  34. package/bin/install-constants.mjs +88 -0
  35. package/bin/install.mjs +1138 -114
  36. package/bin/install.prune.test.mjs +869 -19
  37. package/bin/install.test.mjs +906 -2
  38. package/commands/implement.md +1 -1
  39. package/commands/right-size.md +1 -1
  40. package/docs/CLAUDE.md +1 -0
  41. package/docs/host-pool-health-monitor.md +102 -0
  42. package/docs/references/CLAUDE.md +4 -2
  43. package/docs/references/advisor-tool.md +13 -0
  44. package/docs/references/code-review-enforcement.md +10 -0
  45. package/docs/references/team-advisor-skill.md +14 -0
  46. package/hooks/blocking/CLAUDE.md +1 -0
  47. package/hooks/blocking/code_review_pr_create_gate.py +7 -3
  48. package/hooks/blocking/code_review_push_gate.py +9 -4
  49. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
  50. package/hooks/blocking/config/__init__.py +5 -5
  51. package/hooks/blocking/config/code_review_enforcement_constants.py +4 -1
  52. package/hooks/blocking/config/test_code_review_enforcement_constants.py +5 -0
  53. package/hooks/blocking/config/verified_commit_constants.py +160 -159
  54. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
  55. package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
  56. package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
  57. package/hooks/blocking/test_code_review_push_gate.py +16 -0
  58. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
  59. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
  60. package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
  61. package/hooks/blocking/test_verdict_directory_write_blocker.py +808 -808
  62. package/hooks/blocking/test_verification_verdict_store.py +54 -0
  63. package/hooks/blocking/test_verified_commit_gate.py +581 -581
  64. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
  65. package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
  66. package/hooks/blocking/verification_verdict_store.py +1039 -1036
  67. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
  68. package/hooks/blocking/verifier_verdict_minter.py +280 -280
  69. package/hooks/git-hooks/test_pre_push.py +25 -0
  70. package/hooks/hooks.json +10 -0
  71. package/hooks/hooks_constants/CLAUDE.md +2 -1
  72. package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
  73. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
  74. package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
  75. package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
  76. package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
  77. package/hooks/pyproject.toml +1 -0
  78. package/hooks/validators/CLAUDE.md +1 -0
  79. package/hooks/validators/config/__init__.py +0 -0
  80. package/hooks/validators/config/directory_exemption_constants.py +183 -0
  81. package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
  82. package/hooks/validators/conftest.py +4 -0
  83. package/hooks/validators/ruff_integration.py +49 -5
  84. package/hooks/validators/run_all_validators.py +206 -9
  85. package/hooks/validators/test_directory_exemption_constants.py +185 -0
  86. package/hooks/validators/test_python_antipattern_checks.py +110 -5
  87. package/hooks/validators/test_ruff_integration.py +92 -1
  88. package/hooks/validators/test_run_all_validators.py +115 -68
  89. package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
  90. package/package.json +10 -2
  91. package/rules/CLAUDE.md +1 -0
  92. package/rules/docstring-prose-matches-implementation.md +45 -44
  93. package/rules/state-what-is.md +25 -0
  94. package/rules/verified-commit-gate-skip.md +1 -1
  95. package/scripts/CLAUDE.md +1 -0
  96. package/scripts/Capture-PoolHealth.ps1 +410 -0
  97. package/scripts/_code_review_test_support.py +404 -0
  98. package/scripts/claude_chain_runner.py +141 -1
  99. package/scripts/conftest.py +16 -1
  100. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
  101. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
  102. package/scripts/resolve_worker_spawn.py +626 -626
  103. package/scripts/spawn_grok_batch.py +672 -672
  104. package/scripts/test_claude_chain_runner.py +131 -0
  105. package/scripts/test_invoke_code_review_chain.py +70 -0
  106. package/scripts/test_invoke_code_review_cli.py +192 -0
  107. package/scripts/test_invoke_code_review_contract.py +256 -0
  108. package/scripts/test_invoke_code_review_git.py +123 -0
  109. package/scripts/test_invoke_code_review_mode.py +99 -0
  110. package/scripts/test_resolve_worker_spawn.py +1014 -1014
  111. package/skills/CLAUDE.md +2 -0
  112. package/skills/auditing-claude-config/SKILL.md +114 -114
  113. package/skills/autoconverge/SKILL.md +427 -427
  114. package/skills/autoconverge/reference/convergence.md +24 -3
  115. package/skills/autoconverge/workflow/CLAUDE.md +1 -0
  116. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
  117. package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
  118. package/skills/autoconverge/workflow/converge.mjs +167 -0
  119. package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
  120. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
  121. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
  122. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
  123. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
  124. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
  125. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
  126. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
  127. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
  128. package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
  129. package/skills/closeout/SKILL.md +33 -50
  130. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
  131. package/skills/codex-review/scripts/run_codex_review.py +233 -1
  132. package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
  133. package/skills/condensing-instructions/SKILL.md +81 -0
  134. package/skills/copilot-review/SKILL.md +119 -119
  135. package/skills/e-code-review/SKILL.md +52 -0
  136. package/skills/e-code-review/reference/fix.md +54 -0
  137. package/skills/e-code-review/reference/loop.md +43 -0
  138. package/skills/e-code-review/reference/low.md +57 -0
  139. package/skills/e-code-review/reference/medium.md +153 -0
  140. package/skills/e-code-review/reference/xhigh.md +182 -0
  141. package/skills/e-simplify/SKILL.md +97 -0
  142. package/skills/issue-tracker/SKILL.md +92 -0
  143. package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
  144. package/skills/issue-tracker/reference/handoff-schema.md +64 -0
  145. package/skills/issue-tracker/reference/operation-matrix.md +41 -0
  146. package/skills/orchestrator/SKILL.md +162 -21
  147. package/skills/orchestrator/scripts/status_gate.py +625 -0
  148. package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
  149. package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
  150. package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
  151. package/skills/orchestrator/scripts/test_status_gate.py +439 -0
  152. package/skills/orchestrator-refresh/SKILL.md +110 -35
  153. package/skills/plan-to-pr/SKILL.md +155 -0
  154. package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
  155. package/skills/plan-to-pr/reference/model-routing.md +36 -0
  156. package/skills/plan-to-pr/reference/packet-contract.md +43 -0
  157. package/skills/plan-to-pr/reference/packet-schema.json +57 -0
  158. package/skills/plan-to-pr/reference/process-inventory.md +22 -0
  159. package/skills/plan-to-pr/reference/review-loop.md +33 -0
  160. package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
  161. package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
  162. package/skills/plan-to-pr/reference/task-seeds.md +14 -0
  163. package/skills/plan-to-pr/reference/task-ticket.md +38 -0
  164. package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
  165. package/skills/plan-to-pr/scripts/config/constants.py +193 -0
  166. package/skills/plan-to-pr/scripts/create_packet.py +173 -0
  167. package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
  168. package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
  169. package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
  170. package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
  171. package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
  172. package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
  173. package/skills/plan-to-pr/scripts/validate_run.py +173 -0
  174. package/skills/plan-to-pr/test_skill_contract.py +207 -0
  175. package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
  176. package/skills/pr-converge/SKILL.md +472 -469
  177. package/skills/pr-converge/reference/examples.md +3 -3
  178. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  179. package/skills/pr-converge/reference/ground-rules.md +7 -4
  180. package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
  181. package/skills/pr-converge/reference/per-tick.md +5 -5
  182. package/skills/pr-converge/reference/progress-checklist.md +1 -1
  183. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
  184. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
  185. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
  186. package/skills/pr-converge/test_step5_host_branch.py +1 -1
  187. package/skills/pr-fix-protocol/SKILL.md +1 -1
  188. package/skills/privacy-hygiene/SKILL.md +68 -68
  189. package/skills/prototype/workflows/promotion.md +1 -1
  190. package/skills/release-notes-html/SKILL.md +164 -0
  191. package/skills/task-build/CLAUDE.md +8 -7
  192. package/skills/task-build/SKILL.md +16 -8
  193. package/skills/task-build/reference/tool-routing.md +19 -0
  194. package/scripts/test_invoke_code_review.py +0 -966
  195. package/skills/closeout/reference/issue-body-templates.md +0 -108
@@ -1,131 +1,131 @@
1
- """Unit tests for the verified-commit-message-accuracy PreToolUse hook."""
2
-
3
- import importlib.util
4
- import pathlib
5
- import sys
6
-
7
- _HOOK_DIR = pathlib.Path(__file__).parent
8
- if str(_HOOK_DIR) not in sys.path:
9
- sys.path.insert(0, str(_HOOK_DIR))
10
-
11
- hook_spec = importlib.util.spec_from_file_location(
12
- "verified_commit_message_accuracy_blocker",
13
- _HOOK_DIR / "verified_commit_message_accuracy_blocker.py",
14
- )
15
- assert hook_spec is not None
16
- assert hook_spec.loader is not None
17
- hook_module = importlib.util.module_from_spec(hook_spec)
18
- hook_spec.loader.exec_module(hook_module)
19
- is_guarded_file = hook_module.is_guarded_file
20
- claims_blanket_comment_exemption = hook_module.claims_blanket_comment_exemption
21
- extract_written_text = hook_module.extract_written_text
22
- build_corrective_message = hook_module.build_corrective_message
23
-
24
- OFFENDING_MESSAGE = (
25
- "CORRECTIVE_MESSAGE = (\n"
26
- ' "BLOCKED: [VERIFIED_COMMIT_GATE] This branch surface has no passing "\n'
27
- ' "verification verdict. Spawn the code-verifier agent (Agent tool, "\n'
28
- " \"subagent_type 'code-verifier') with the task texts, the diff scope, \"\n"
29
- ' "and recorded baselines; when it finishes with a clean verdict the "\n'
30
- ' "SubagentStop hook mints the verdict and this command will pass. Any "\n'
31
- ' "file change after verification invalidates the verdict, so verify "\n'
32
- ' "last. Docs-, docstring-, comment-, and test-only surfaces are exempt "\n'
33
- ' "automatically."\n'
34
- ")\n"
35
- )
36
- ACCURATE_DOCS_EXEMPTION_MENTIONING_COMMENTS = (
37
- "Comments inside Python files are stripped; docs are exempt "
38
- "automatically by extension."
39
- )
40
- ACCURATE_MESSAGE = (
41
- "CORRECTIVE_MESSAGE = (\n"
42
- ' "BLOCKED: [VERIFIED_COMMIT_GATE] ... Docs and images are exempt by "\n'
43
- ' "extension, and Python files whose docstring- and comment-stripped AST "\n'
44
- ' "is unchanged."\n'
45
- ")\n"
46
- )
47
-
48
-
49
- def test_constants_file_is_guarded() -> None:
50
- assert is_guarded_file(
51
- "/repo/.claude/hooks/blocking/config/verified_commit_constants.py"
52
- )
53
-
54
-
55
- def test_unrelated_file_is_not_guarded() -> None:
56
- assert not is_guarded_file("/repo/.claude/hooks/blocking/gh_body_arg_blocker.py")
57
-
58
-
59
- def test_blanket_comment_exemption_claim_is_detected() -> None:
60
- assert claims_blanket_comment_exemption(OFFENDING_MESSAGE)
61
-
62
-
63
- def test_blanket_claim_detected_regardless_of_leading_words() -> None:
64
- assert claims_blanket_comment_exemption(
65
- "Comment-only surfaces are exempt automatically."
66
- )
67
-
68
-
69
- def test_accurate_exemption_wording_passes() -> None:
70
- assert not claims_blanket_comment_exemption(ACCURATE_MESSAGE)
71
-
72
-
73
- def test_accurate_docs_exemption_mentioning_comments_passes() -> None:
74
- assert not claims_blanket_comment_exemption(
75
- ACCURATE_DOCS_EXEMPTION_MENTIONING_COMMENTS
76
- )
77
-
78
-
79
- def test_comma_joined_docs_exemption_mentioning_comments_passes() -> None:
80
- assert not claims_blanket_comment_exemption(
81
- "Comments are handled, and docs are exempt automatically."
82
- )
83
-
84
-
85
- def test_python_ast_clause_mentioning_comments_passes() -> None:
86
- assert not claims_blanket_comment_exemption(
87
- "Python comment-stripped AST changes and docs are exempt automatically "
88
- "by extension"
89
- )
90
-
91
-
92
- def test_single_clause_python_ast_exemption_passes() -> None:
93
- assert not claims_blanket_comment_exemption(
94
- "Python files whose comment-stripped AST is unchanged are exempt "
95
- "automatically."
96
- )
97
-
98
-
99
- def test_commentary_word_stem_passes() -> None:
100
- assert not claims_blanket_comment_exemption(
101
- "Our commentary on the approach is exempt automatically from blame."
102
- )
103
-
104
-
105
- def test_corrective_message_names_only_the_two_real_exemptions() -> None:
106
- corrective_message = build_corrective_message()
107
- assert "exempt by extension" in corrective_message
108
- assert "docstring- and comment-stripped AST" in corrective_message
109
- assert "test file" not in corrective_message
110
- assert "by name convention" not in corrective_message
111
-
112
-
113
- def test_message_without_exemption_claim_passes() -> None:
114
- assert not claims_blanket_comment_exemption(
115
- 'CORRECTIVE_MESSAGE = "Spawn the code-verifier agent to earn a verdict."'
116
- )
117
-
118
-
119
- def test_write_content_is_extracted() -> None:
120
- written_text = extract_written_text({"content": OFFENDING_MESSAGE})
121
- assert claims_blanket_comment_exemption(written_text)
122
-
123
-
124
- def test_edit_new_string_is_extracted() -> None:
125
- written_text = extract_written_text({"new_string": OFFENDING_MESSAGE})
126
- assert claims_blanket_comment_exemption(written_text)
127
-
128
-
129
- def test_edit_new_string_with_accurate_wording_is_clean() -> None:
130
- written_text = extract_written_text({"new_string": ACCURATE_MESSAGE})
131
- assert not claims_blanket_comment_exemption(written_text)
1
+ """Unit tests for the verified-commit-message-accuracy PreToolUse hook."""
2
+
3
+ import importlib.util
4
+ import pathlib
5
+ import sys
6
+
7
+ _HOOK_DIR = pathlib.Path(__file__).parent
8
+ if str(_HOOK_DIR) not in sys.path:
9
+ sys.path.insert(0, str(_HOOK_DIR))
10
+
11
+ hook_spec = importlib.util.spec_from_file_location(
12
+ "verified_commit_message_accuracy_blocker",
13
+ _HOOK_DIR / "verified_commit_message_accuracy_blocker.py",
14
+ )
15
+ assert hook_spec is not None
16
+ assert hook_spec.loader is not None
17
+ hook_module = importlib.util.module_from_spec(hook_spec)
18
+ hook_spec.loader.exec_module(hook_module)
19
+ is_guarded_file = hook_module.is_guarded_file
20
+ claims_blanket_comment_exemption = hook_module.claims_blanket_comment_exemption
21
+ extract_written_text = hook_module.extract_written_text
22
+ build_corrective_message = hook_module.build_corrective_message
23
+
24
+ OFFENDING_MESSAGE = (
25
+ "CORRECTIVE_MESSAGE = (\n"
26
+ ' "BLOCKED: [VERIFIED_COMMIT_GATE] This branch surface has no passing "\n'
27
+ ' "verification verdict. Spawn the code-verifier agent (Agent tool, "\n'
28
+ " \"subagent_type 'code-verifier') with the task texts, the diff scope, \"\n"
29
+ ' "and recorded baselines; when it finishes with a clean verdict the "\n'
30
+ ' "SubagentStop hook mints the verdict and this command will pass. Any "\n'
31
+ ' "file change after verification invalidates the verdict, so verify "\n'
32
+ ' "last. Docs-, docstring-, comment-, and test-only surfaces are exempt "\n'
33
+ ' "automatically."\n'
34
+ ")\n"
35
+ )
36
+ ACCURATE_DOCS_EXEMPTION_MENTIONING_COMMENTS = (
37
+ "Comments inside Python files are stripped; docs are exempt "
38
+ "automatically by extension."
39
+ )
40
+ ACCURATE_MESSAGE = (
41
+ "CORRECTIVE_MESSAGE = (\n"
42
+ ' "BLOCKED: [VERIFIED_COMMIT_GATE] ... Docs and images are exempt by "\n'
43
+ ' "extension, and Python files whose docstring- and comment-stripped AST "\n'
44
+ ' "is unchanged."\n'
45
+ ")\n"
46
+ )
47
+
48
+
49
+ def test_constants_file_is_guarded() -> None:
50
+ assert is_guarded_file(
51
+ "/repo/.claude/hooks/blocking/config/verified_commit_constants.py"
52
+ )
53
+
54
+
55
+ def test_unrelated_file_is_not_guarded() -> None:
56
+ assert not is_guarded_file("/repo/.claude/hooks/blocking/gh_body_arg_blocker.py")
57
+
58
+
59
+ def test_blanket_comment_exemption_claim_is_detected() -> None:
60
+ assert claims_blanket_comment_exemption(OFFENDING_MESSAGE)
61
+
62
+
63
+ def test_blanket_claim_detected_regardless_of_leading_words() -> None:
64
+ assert claims_blanket_comment_exemption(
65
+ "Comment-only surfaces are exempt automatically."
66
+ )
67
+
68
+
69
+ def test_accurate_exemption_wording_passes() -> None:
70
+ assert not claims_blanket_comment_exemption(ACCURATE_MESSAGE)
71
+
72
+
73
+ def test_accurate_docs_exemption_mentioning_comments_passes() -> None:
74
+ assert not claims_blanket_comment_exemption(
75
+ ACCURATE_DOCS_EXEMPTION_MENTIONING_COMMENTS
76
+ )
77
+
78
+
79
+ def test_comma_joined_docs_exemption_mentioning_comments_passes() -> None:
80
+ assert not claims_blanket_comment_exemption(
81
+ "Comments are handled, and docs are exempt automatically."
82
+ )
83
+
84
+
85
+ def test_python_ast_clause_mentioning_comments_passes() -> None:
86
+ assert not claims_blanket_comment_exemption(
87
+ "Python comment-stripped AST changes and docs are exempt automatically "
88
+ "by extension"
89
+ )
90
+
91
+
92
+ def test_single_clause_python_ast_exemption_passes() -> None:
93
+ assert not claims_blanket_comment_exemption(
94
+ "Python files whose comment-stripped AST is unchanged are exempt "
95
+ "automatically."
96
+ )
97
+
98
+
99
+ def test_commentary_word_stem_passes() -> None:
100
+ assert not claims_blanket_comment_exemption(
101
+ "Our commentary on the approach is exempt automatically from blame."
102
+ )
103
+
104
+
105
+ def test_corrective_message_names_only_the_two_real_exemptions() -> None:
106
+ corrective_message = build_corrective_message()
107
+ assert "exempt by extension" in corrective_message
108
+ assert "docstring- and comment-stripped AST" in corrective_message
109
+ assert "test file" not in corrective_message
110
+ assert "by name convention" not in corrective_message
111
+
112
+
113
+ def test_message_without_exemption_claim_passes() -> None:
114
+ assert not claims_blanket_comment_exemption(
115
+ 'CORRECTIVE_MESSAGE = "Spawn the code-verifier agent to earn a verdict."'
116
+ )
117
+
118
+
119
+ def test_write_content_is_extracted() -> None:
120
+ written_text = extract_written_text({"content": OFFENDING_MESSAGE})
121
+ assert claims_blanket_comment_exemption(written_text)
122
+
123
+
124
+ def test_edit_new_string_is_extracted() -> None:
125
+ written_text = extract_written_text({"new_string": OFFENDING_MESSAGE})
126
+ assert claims_blanket_comment_exemption(written_text)
127
+
128
+
129
+ def test_edit_new_string_with_accurate_wording_is_clean() -> None:
130
+ written_text = extract_written_text({"new_string": ACCURATE_MESSAGE})
131
+ assert not claims_blanket_comment_exemption(written_text)