claude-dev-env 1.94.0 → 2.0.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 (280) hide show
  1. package/_shared/advisor/CLAUDE.md +2 -2
  2. package/_shared/advisor/advisor-protocol.md +41 -33
  3. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +17 -13
  4. package/_shared/advisor/scripts/model_tier_run_validator.py +27 -18
  5. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +95 -25
  6. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +17 -17
  7. package/_shared/advisor/scripts/tier_model_ids.py +18 -18
  8. package/_shared/pr-loop/CLAUDE.md +1 -0
  9. package/_shared/pr-loop/scripts/CLAUDE.md +2 -1
  10. package/_shared/pr-loop/scripts/README.md +1 -0
  11. package/_shared/pr-loop/scripts/code_rules_gate.py +253 -1980
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +32 -0
  13. package/_shared/pr-loop/scripts/code_rules_gate_parts/__init__.py +7 -0
  14. package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +268 -0
  15. package/_shared/pr-loop/scripts/code_rules_gate_parts/enforcer_loading.py +172 -0
  16. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_arguments.py +70 -0
  17. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +326 -0
  18. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +85 -0
  19. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +331 -0
  20. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +369 -0
  21. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/conftest.py +14 -0
  22. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_added_line_maps.py +118 -0
  23. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_enforcer_loading.py +17 -0
  24. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_arguments.py +29 -0
  25. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_running.py +99 -0
  26. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_blob_readers.py +69 -0
  27. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_file_sets.py +137 -0
  28. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +116 -0
  29. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_violation_scoping.py +75 -0
  30. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_wrapper_plumb_check.py +49 -0
  31. package/_shared/pr-loop/scripts/code_rules_gate_parts/violation_scoping.py +328 -0
  32. package/_shared/pr-loop/scripts/code_rules_gate_parts/wrapper_plumb_check.py +206 -0
  33. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +24 -17
  34. package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +1 -0
  35. package/_shared/pr-loop/scripts/reviews_disabled.py +19 -2
  36. package/_shared/pr-loop/scripts/test_code_rules_gate.py +278 -0
  37. package/_shared/pr-loop/scripts/tests/test_code_rules_gate_constants.py +6 -39
  38. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +43 -0
  39. package/_shared/pr-loop/worker-spawn.md +186 -0
  40. package/agents/code-verifier.md +1 -1
  41. package/bin/CLAUDE.md +10 -1
  42. package/bin/ever-shipped-skills.mjs +73 -0
  43. package/bin/expand_home_directory_tokens.mjs +1 -1
  44. package/bin/install.mjs +140 -7
  45. package/bin/install.prune.test.mjs +457 -0
  46. package/docs/CODE_RULES.md +1 -1
  47. package/hooks/advisory/refactor_guard.py +3 -4
  48. package/hooks/blocking/CLAUDE.md +7 -1
  49. package/hooks/blocking/block_main_commit.py +2 -2
  50. package/hooks/blocking/claude_md_orphan_file_blocker.py +75 -699
  51. package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +28 -0
  52. package/hooks/blocking/claude_md_orphan_file_blocker_parts/__init__.py +1 -0
  53. package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/__init__.py +1 -0
  54. package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/orphan_blocker_constants.py +18 -0
  55. package/hooks/blocking/claude_md_orphan_file_blocker_parts/decision.py +81 -0
  56. package/hooks/blocking/claude_md_orphan_file_blocker_parts/references.py +307 -0
  57. package/hooks/blocking/claude_md_orphan_file_blocker_parts/scan_plan.py +124 -0
  58. package/hooks/blocking/claude_md_orphan_file_blocker_parts/subtree_scan.py +179 -0
  59. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/conftest.py +10 -0
  60. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_decision.py +34 -0
  61. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_references.py +42 -0
  62. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_scan_plan.py +27 -0
  63. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_subtree_scan.py +30 -0
  64. package/hooks/blocking/code_rules_boolean_mustcheck.py +1 -1
  65. package/hooks/blocking/code_rules_enforcer.py +4 -0
  66. package/hooks/blocking/code_rules_mock_completeness.py +1 -1
  67. package/hooks/blocking/code_rules_optional_params.py +2 -2
  68. package/hooks/blocking/code_rules_shared.py +83 -1
  69. package/hooks/blocking/code_rules_test_assertions.py +1 -1
  70. package/hooks/blocking/code_rules_test_layout.py +9 -3
  71. package/hooks/blocking/code_rules_typeddict_stub.py +1 -1
  72. package/hooks/blocking/gh_pr_author_enforcer.py +1 -1
  73. package/hooks/blocking/inventory_intent_records/CLAUDE.md +26 -0
  74. package/hooks/blocking/inventory_intent_records/__init__.py +1 -0
  75. package/hooks/blocking/inventory_intent_records/config/__init__.py +1 -0
  76. package/hooks/blocking/inventory_intent_records/config/intent_records_constants.py +20 -0
  77. package/hooks/blocking/inventory_intent_records/records.py +271 -0
  78. package/hooks/blocking/inventory_intent_records/tests/conftest.py +10 -0
  79. package/hooks/blocking/inventory_intent_records/tests/test_records.py +80 -0
  80. package/hooks/blocking/package_inventory_stale_blocker.py +54 -384
  81. package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +26 -0
  82. package/hooks/blocking/package_inventory_stale_blocker_parts/__init__.py +1 -0
  83. package/hooks/blocking/package_inventory_stale_blocker_parts/config/__init__.py +1 -0
  84. package/hooks/blocking/package_inventory_stale_blocker_parts/config/inventory_blocker_constants.py +16 -0
  85. package/hooks/blocking/package_inventory_stale_blocker_parts/decision.py +84 -0
  86. package/hooks/blocking/package_inventory_stale_blocker_parts/inventory_detection.py +307 -0
  87. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/conftest.py +10 -0
  88. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_decision.py +38 -0
  89. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_inventory_detection.py +61 -0
  90. package/hooks/blocking/pii_payload_scan.py +138 -42
  91. package/hooks/blocking/pii_prevention_blocker.py +185 -291
  92. package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +24 -0
  93. package/hooks/blocking/pii_prevention_blocker_parts/__init__.py +1 -0
  94. package/hooks/blocking/pii_prevention_blocker_parts/config/__init__.py +1 -0
  95. package/hooks/blocking/pii_prevention_blocker_parts/config/repository_resolution_constants.py +28 -0
  96. package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +214 -0
  97. package/hooks/blocking/pii_prevention_blocker_parts/repository_resolution.py +208 -0
  98. package/hooks/blocking/plain_language_blocker.py +138 -4
  99. package/hooks/blocking/pr_description_command_parser.py +8 -4
  100. package/hooks/blocking/precommit_code_rules_gate.py +3 -3
  101. package/hooks/blocking/sensitive_file_protector.py +114 -48
  102. package/hooks/blocking/tdd_enforcer.py +97 -601
  103. package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +30 -0
  104. package/hooks/blocking/tdd_enforcer_parts/__init__.py +1 -0
  105. package/hooks/blocking/tdd_enforcer_parts/candidate_paths.py +142 -0
  106. package/hooks/blocking/tdd_enforcer_parts/config/__init__.py +1 -0
  107. package/hooks/blocking/tdd_enforcer_parts/config/tdd_enforcer_constants.py +32 -0
  108. package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +268 -0
  109. package/hooks/blocking/tdd_enforcer_parts/decisions.py +92 -0
  110. package/hooks/blocking/tdd_enforcer_parts/freshness.py +80 -0
  111. package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +63 -0
  112. package/hooks/blocking/tdd_enforcer_parts/path_classification.py +119 -0
  113. package/hooks/blocking/tdd_enforcer_parts/tests/conftest.py +10 -0
  114. package/hooks/blocking/tdd_enforcer_parts/tests/test_candidate_paths.py +31 -0
  115. package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +30 -0
  116. package/hooks/blocking/tdd_enforcer_parts/tests/test_decisions.py +34 -0
  117. package/hooks/blocking/tdd_enforcer_parts/tests/test_freshness.py +28 -0
  118. package/hooks/blocking/tdd_enforcer_parts/tests/test_git_tracking.py +48 -0
  119. package/hooks/blocking/tdd_enforcer_parts/tests/test_path_classification.py +36 -0
  120. package/hooks/blocking/test_code_rules_enforcer_scratchpad.py +105 -0
  121. package/hooks/blocking/test_code_rules_shared.py +181 -0
  122. package/hooks/blocking/test_inventory_deadlock_resolution.py +154 -0
  123. package/hooks/blocking/test_pii_payload_scan.py +168 -0
  124. package/hooks/blocking/test_plain_language_blocker_allowlist.py +184 -0
  125. package/hooks/blocking/test_sensitive_file_protector.py +185 -0
  126. package/hooks/blocking/test_tdd_enforcer_restore.py +108 -0
  127. package/hooks/blocking/test_tdd_enforcer_scratchpad.py +105 -0
  128. package/hooks/blocking/tests/conftest.py +10 -0
  129. package/hooks/blocking/tests/test_pii_prevention_blocker.py +260 -0
  130. package/hooks/blocking/tests/test_repository_exemption.py +105 -0
  131. package/hooks/blocking/tests/test_repository_resolution.py +108 -0
  132. package/hooks/diagnostic/hook_log_extractor.py +12 -10
  133. package/hooks/git-hooks/post_commit.py +3 -4
  134. package/hooks/hooks_constants/CLAUDE.md +4 -2
  135. package/hooks/hooks_constants/banned_identifiers_constants.py +0 -1
  136. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  137. package/hooks/hooks_constants/harness_scratchpad_constants.py +17 -0
  138. package/hooks/hooks_constants/local_identity.py +59 -8
  139. package/hooks/hooks_constants/pii_prevention_constants.py +0 -6
  140. package/hooks/hooks_constants/plain_language_blocker_constants.py +5 -0
  141. package/hooks/hooks_constants/sensitive_file_protector_constants.py +42 -0
  142. package/hooks/hooks_constants/test_local_identity.py +105 -3
  143. package/hooks/pyproject.toml +52 -4
  144. package/hooks/session/plugin_data_dir_cleanup.py +0 -1
  145. package/hooks/validation/mypy_validator.py +2 -2
  146. package/hooks/validators/CLAUDE.md +1 -1
  147. package/hooks/validators/README.md +2 -0
  148. package/hooks/validators/health_check.py +1 -0
  149. package/hooks/validators/mypy_integration.py +2 -0
  150. package/hooks/validators/python_style_checks.py +114 -136
  151. package/hooks/validators/python_style_helpers.py +95 -0
  152. package/hooks/validators/ruff_integration.py +3 -0
  153. package/hooks/validators/test_python_style_checks.py +0 -164
  154. package/hooks/validators/test_python_style_checks_decorator_gap.py +119 -0
  155. package/hooks/validators/test_python_style_fixes.py +251 -0
  156. package/hooks/validators/test_python_style_helpers.py +125 -0
  157. package/hooks/workflow/auto_formatter.py +5 -4
  158. package/package.json +1 -1
  159. package/rules/CLAUDE.md +1 -0
  160. package/rules/anti-corollary-tests.md +69 -0
  161. package/rules/bdd.md +1 -3
  162. package/rules/code-reviews.md +1 -1
  163. package/rules/gh-paginate.md +1 -1
  164. package/rules/plain-language.md +2 -0
  165. package/scripts/CLAUDE.md +4 -0
  166. package/scripts/dev_env_scripts_constants/CLAUDE.md +6 -4
  167. package/scripts/dev_env_scripts_constants/code_review_constants.py +71 -0
  168. package/scripts/dev_env_scripts_constants/grok_worker_constants.py +435 -0
  169. package/scripts/dev_env_scripts_constants/timing.py +7 -1
  170. package/scripts/grok_headless_runner.py +294 -0
  171. package/scripts/grok_worker_preflight.py +410 -0
  172. package/scripts/invoke_code_review.py +463 -0
  173. package/scripts/resolve_worker_spawn.py +619 -0
  174. package/scripts/spawn_grok_batch.py +672 -0
  175. package/scripts/test_grok_headless_runner.py +626 -0
  176. package/scripts/test_grok_worker_preflight.py +1054 -0
  177. package/scripts/test_invoke_code_review.py +672 -0
  178. package/scripts/test_resolve_worker_spawn.py +1014 -0
  179. package/scripts/test_spawn_grok_batch.py +1017 -0
  180. package/skills/CLAUDE.md +6 -3
  181. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +72 -13
  182. package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +121 -14
  183. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +78 -0
  184. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +121 -0
  185. package/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +196 -6
  186. package/skills/autoconverge/CLAUDE.md +3 -3
  187. package/skills/autoconverge/SKILL.md +9 -3
  188. package/skills/autoconverge/reference/CLAUDE.md +2 -2
  189. package/skills/autoconverge/reference/convergence.md +33 -11
  190. package/skills/autoconverge/reference/stop-conditions.md +16 -5
  191. package/skills/autoconverge/workflow/CLAUDE.md +2 -1
  192. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +7 -2
  193. package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +300 -0
  194. package/skills/autoconverge/workflow/converge.contract.test.mjs +5 -5
  195. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +29 -29
  196. package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
  197. package/skills/autoconverge/workflow/converge.mjs +202 -18
  198. package/skills/bugteam/CLAUDE.md +2 -2
  199. package/skills/bugteam/CONSTRAINTS.md +3 -2
  200. package/skills/bugteam/PROMPTS.md +7 -6
  201. package/skills/bugteam/SKILL.md +18 -13
  202. package/skills/bugteam/reference/README.md +2 -3
  203. package/skills/bugteam/reference/audit-and-teammates.md +215 -35
  204. package/skills/bugteam/reference/design-rationale.md +1 -1
  205. package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -1
  206. package/skills/bugteam/reference/team-setup.md +8 -2
  207. package/skills/closeout/SKILL.md +153 -0
  208. package/skills/closeout/reference/handoff-prompt-template.md +72 -0
  209. package/skills/closeout/reference/issue-body-templates.md +108 -0
  210. package/skills/closeout/reference/pii-redaction-checklist.md +36 -0
  211. package/skills/codex-review/CLAUDE.md +46 -0
  212. package/skills/codex-review/SKILL.md +181 -0
  213. package/skills/codex-review/reference/CLAUDE.md +15 -0
  214. package/skills/codex-review/reference/cli-contract.md +253 -0
  215. package/skills/codex-review/reference/loop-integration.md +118 -0
  216. package/skills/codex-review/scripts/codex_down_classifier.py +98 -0
  217. package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +18 -0
  218. package/skills/codex-review/scripts/codex_review_scripts_constants/__init__.py +1 -0
  219. package/skills/codex-review/scripts/codex_review_scripts_constants/classifier_constants.py +35 -0
  220. package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +86 -0
  221. package/skills/codex-review/scripts/codex_review_scripts_constants/findings_constants.py +18 -0
  222. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +45 -0
  223. package/skills/codex-review/scripts/codex_usage_probe.py +573 -0
  224. package/skills/codex-review/scripts/fixtures/auth_failure_synthetic.txt +1 -0
  225. package/skills/codex-review/scripts/fixtures/config_load_failure_v0.125.0.txt +1 -0
  226. package/skills/codex-review/scripts/fixtures/freeform_findings_v0.144.3.txt +6 -0
  227. package/skills/codex-review/scripts/fixtures/model_rejection_v0.125.0.jsonl +5 -0
  228. package/skills/codex-review/scripts/fixtures/structured_findings.txt +13 -0
  229. package/skills/codex-review/scripts/fixtures/success_stream_v0.144.3.jsonl +6 -0
  230. package/skills/codex-review/scripts/fixtures/unknown_failure_synthetic.txt +1 -0
  231. package/skills/codex-review/scripts/fixtures/usage_limit_synthetic.txt +1 -0
  232. package/skills/codex-review/scripts/parse_codex_findings.py +207 -0
  233. package/skills/codex-review/scripts/run_codex_review.py +415 -0
  234. package/skills/codex-review/scripts/test_codex_down_classifier.py +143 -0
  235. package/skills/codex-review/scripts/test_codex_usage_probe.py +678 -0
  236. package/skills/codex-review/scripts/test_parse_codex_findings.py +130 -0
  237. package/skills/codex-review/scripts/test_run_codex_review.py +812 -0
  238. package/skills/codex-review/test_skill_scaffold.py +192 -0
  239. package/skills/grok-spawn/CLAUDE.md +28 -0
  240. package/skills/grok-spawn/SKILL.md +226 -0
  241. package/skills/grok-spawn/reference/flag-profiles.md +132 -0
  242. package/skills/grok-spawn/reference/worker-briefs.md +152 -0
  243. package/skills/grokify/SKILL.md +9 -1
  244. package/skills/grokify/capability-claims.test.mjs +28 -0
  245. package/skills/grokify/evals/README.md +72 -0
  246. package/skills/grokify/evals/parse-payload.test.mjs +171 -0
  247. package/skills/grokify/evals/run-capability-evals.mjs +545 -0
  248. package/skills/orchestrator/SKILL.md +32 -22
  249. package/skills/orchestrator-refresh/SKILL.md +12 -8
  250. package/skills/pr-converge/CLAUDE.md +1 -1
  251. package/skills/pr-converge/SKILL.md +34 -13
  252. package/skills/pr-converge/reference/convergence-gates.md +42 -15
  253. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  254. package/skills/pr-converge/reference/ground-rules.md +1 -1
  255. package/skills/pr-converge/reference/per-tick.md +130 -42
  256. package/skills/pr-converge/reference/state-schema.md +10 -0
  257. package/skills/pr-converge/scripts/CLAUDE.md +2 -0
  258. package/skills/pr-converge/scripts/_pr_converge_path_setup.py +5 -1
  259. package/skills/pr-converge/scripts/check_convergence.py +605 -29
  260. package/skills/pr-converge/scripts/check_convergence_availability.py +232 -0
  261. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -235
  262. package/skills/pr-converge/scripts/check_convergence_thread_gates.py +1 -1
  263. package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -2
  264. package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +4 -0
  265. package/skills/pr-converge/scripts/test_check_convergence.py +71 -3
  266. package/skills/pr-converge/scripts/test_check_convergence_availability.py +326 -0
  267. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -0
  268. package/skills/pr-converge/scripts/test_check_convergence_contract.py +89 -17
  269. package/skills/pr-converge/scripts/test_check_convergence_fixture.py +179 -0
  270. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -68
  271. package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +24 -0
  272. package/skills/pr-converge/test_step5_host_branch.py +106 -0
  273. package/skills/pr-fix-protocol/SKILL.md +65 -0
  274. package/skills/pr-loop-cloud-transport/SKILL.md +2 -0
  275. package/skills/reviewer-gates/SKILL.md +7 -5
  276. package/skills/skill-builder/references/skill-modularity.md +1 -1
  277. package/skills/team-advisor/SKILL.md +16 -12
  278. package/system-prompts/software-engineer.xml +7 -6
  279. package/hooks/validators/test_verify_paths.py +0 -32
  280. package/hooks/validators/verify_paths.py +0 -57
@@ -8,9 +8,11 @@ import sys
8
8
  from pathlib import Path
9
9
  from unittest.mock import patch
10
10
 
11
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
12
-
13
- from hooks_constants import local_identity # noqa: E402
11
+ try:
12
+ from hooks_constants import local_identity
13
+ except ImportError:
14
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
15
+ from hooks_constants import local_identity
14
16
 
15
17
  ALL_NAS_ENV_VARS = ("CLAUDE_NAS_HOST", "CLAUDE_NAS_SSH_USER", "CLAUDE_NAS_SSH_PORT")
16
18
 
@@ -134,6 +136,106 @@ class TestPiiExemptRepositorySlugs:
134
136
  assert slugs == frozenset({"fileowner/file-repo"})
135
137
 
136
138
 
139
+ class TestPiiAllowlistedValuesByRepository:
140
+ def test_reads_the_mapping_lowercasing_slugs_and_keeping_values_exact(
141
+ self, tmp_path: Path
142
+ ) -> None:
143
+ allowed_value = "owner.fixture" + "@" + "acme-corp" + ".example" + ".io"
144
+ identity_path = tmp_path / "local-identity.json"
145
+ identity_path.write_text(
146
+ json.dumps(
147
+ {"pii_allowlisted_values": {"Owner/Private-Repo": [allowed_value]}}
148
+ ),
149
+ encoding="utf-8",
150
+ )
151
+ with patch.dict(
152
+ os.environ,
153
+ {"CLAUDE_LOCAL_IDENTITY_PATH": str(identity_path)},
154
+ clear=False,
155
+ ):
156
+ values_by_slug = local_identity.pii_allowlisted_values_by_repository()
157
+ assert values_by_slug == {"owner/private-repo": frozenset({allowed_value})}
158
+
159
+ def test_returns_empty_mapping_when_the_file_is_missing(
160
+ self, tmp_path: Path
161
+ ) -> None:
162
+ with patch.dict(
163
+ os.environ,
164
+ {"CLAUDE_LOCAL_IDENTITY_PATH": str(tmp_path / "absent.json")},
165
+ clear=False,
166
+ ):
167
+ assert local_identity.pii_allowlisted_values_by_repository() == {}
168
+
169
+ def test_returns_empty_mapping_when_the_json_is_corrupt(
170
+ self, tmp_path: Path
171
+ ) -> None:
172
+ identity_path = tmp_path / "local-identity.json"
173
+ identity_path.write_text("{ not valid json", encoding="utf-8")
174
+ with patch.dict(
175
+ os.environ,
176
+ {"CLAUDE_LOCAL_IDENTITY_PATH": str(identity_path)},
177
+ clear=False,
178
+ ):
179
+ assert local_identity.pii_allowlisted_values_by_repository() == {}
180
+
181
+ def test_returns_empty_mapping_when_the_key_is_absent(
182
+ self, tmp_path: Path
183
+ ) -> None:
184
+ identity_path = tmp_path / "local-identity.json"
185
+ identity_path.write_text(
186
+ json.dumps({"nas": {"host": "10.0.0.5"}}), encoding="utf-8"
187
+ )
188
+ with patch.dict(
189
+ os.environ,
190
+ {"CLAUDE_LOCAL_IDENTITY_PATH": str(identity_path)},
191
+ clear=False,
192
+ ):
193
+ assert local_identity.pii_allowlisted_values_by_repository() == {}
194
+
195
+ def test_drops_blank_slugs_and_non_list_value_entries(
196
+ self, tmp_path: Path
197
+ ) -> None:
198
+ allowed_value = "keep.fixture" + "@" + "acme-corp" + ".example" + ".io"
199
+ identity_path = tmp_path / "local-identity.json"
200
+ identity_path.write_text(
201
+ json.dumps(
202
+ {
203
+ "pii_allowlisted_values": {
204
+ " ": [allowed_value],
205
+ "Owner/Repo": allowed_value,
206
+ "Owner/Kept": [allowed_value, 7],
207
+ }
208
+ }
209
+ ),
210
+ encoding="utf-8",
211
+ )
212
+ with patch.dict(
213
+ os.environ,
214
+ {"CLAUDE_LOCAL_IDENTITY_PATH": str(identity_path)},
215
+ clear=False,
216
+ ):
217
+ values_by_slug = local_identity.pii_allowlisted_values_by_repository()
218
+ assert values_by_slug == {"owner/kept": frozenset({allowed_value})}
219
+
220
+
221
+ class TestLocalIdentityPathOverride:
222
+ def test_prefers_the_env_path_over_the_home_directory_file(
223
+ self, tmp_path: Path
224
+ ) -> None:
225
+ override_path = tmp_path / "override" / "local-identity.json"
226
+ override_path.parent.mkdir()
227
+ override_path.write_text(
228
+ json.dumps({"nas": {"host": "10.9.9.9"}}), encoding="utf-8"
229
+ )
230
+ with patch.dict(
231
+ os.environ,
232
+ {"CLAUDE_LOCAL_IDENTITY_PATH": str(override_path)},
233
+ clear=False,
234
+ ), patch.object(Path, "home", return_value=tmp_path):
235
+ _clear_nas_env()
236
+ assert local_identity.nas_host() == "10.9.9.9"
237
+
238
+
137
239
  class TestDenyMessagesQuoteTheResolvedHost:
138
240
  def should_include_the_resolved_host_and_port_in_the_bare_binary_message(
139
241
  self,
@@ -9,10 +9,23 @@
9
9
  mypy_path = "."
10
10
  python_version = "3.13"
11
11
  ignore_missing_imports = true
12
- warn_unused_ignores = true
12
+ warn_unused_ignores = false
13
13
  warn_redundant_casts = true
14
14
  no_implicit_optional = true
15
15
  strict_equality = true
16
+ exclude = [
17
+ "validators/test_files/",
18
+ "test_",
19
+ "abbreviation_checks.py",
20
+ "git_checks.py",
21
+ "exempt_paths.py",
22
+ "code_rules_typeddict_stub.py",
23
+ ]
24
+
25
+
26
+ [[tool.mypy.overrides]]
27
+ module = ["exempt_paths", "code_rules_path_utils", "gh_pr_author_enforcer"]
28
+ warn_unused_ignores = false
16
29
 
17
30
  [[tool.mypy.overrides]]
18
31
  module = "tests.*"
@@ -26,6 +39,7 @@ extend-exclude = [
26
39
  ".claude",
27
40
  "node_modules",
28
41
  "__pycache__",
42
+ "validators/test_files",
29
43
  ]
30
44
 
31
45
  [tool.ruff.lint]
@@ -39,16 +53,50 @@ select = [
39
53
  "SIM",
40
54
  "PL",
41
55
  ]
56
+ # Principled + pure-style ignores (#51/#57). Non-negotiable defect classes stay selected.
42
57
  ignore = [
43
58
  "E501",
59
+ "E402",
60
+ "UP038",
61
+ "UP006",
62
+ "UP007",
63
+ "UP015",
64
+ "UP017",
65
+ "UP020",
66
+ "UP024",
67
+ "UP035",
68
+ "UP045",
69
+ "I001",
70
+ "B009",
71
+ "F541",
72
+ "PLR0911",
73
+ "PLR0912",
44
74
  "PLR0913",
75
+ "PLR0915",
76
+ "PLR1714",
45
77
  "PLR2004",
78
+ "PLR5501",
79
+ "PLC0414",
80
+ "PLC0415",
81
+ "SIM101",
82
+ "SIM102",
83
+ "SIM103",
84
+ "SIM105",
85
+ "SIM109",
86
+ "SIM110",
87
+ "SIM113",
88
+ "SIM114",
89
+ "SIM117",
90
+ "SIM300",
46
91
  ]
47
92
 
48
93
  [tool.ruff.lint.per-file-ignores]
49
- "test_*.py" = ["B011", "PLR2004"]
50
- "*_test.py" = ["B011", "PLR2004"]
51
- "conftest.py" = ["B011"]
94
+ # Residual production carve-outs re-homed on #57 (gate friction on multi-line touch).
95
+ "validators/run_all_validators.py" = ["PLW1510"]
96
+ "validators/exempt_paths.py" = ["F401"]
97
+ "test_*.py" = ["B011", "PLR2004", "F401", "F841", "PLW1510", "B905", "B033", "SIM115", "B007", "B018", "B904"]
98
+ "*_test.py" = ["B011", "PLR2004", "F401", "F841", "PLW1510", "B905", "B033", "SIM115", "B007", "B018", "B904"]
99
+ "conftest.py" = ["B011", "F401", "F841", "PLW1510"]
52
100
 
53
101
  [tool.coverage.run]
54
102
  branch = true
@@ -13,7 +13,6 @@ separate from the EEXIST fixes in v2.1.70-v2.1.72.
13
13
  """
14
14
 
15
15
  import os
16
- import sys
17
16
 
18
17
  PLUGINS_DATA_DIRECTORY = os.path.join(
19
18
  os.path.expanduser("~"), ".claude", "plugins", "data"
@@ -70,7 +70,7 @@ def discover_project_root(target_file: str) -> Path | None:
70
70
  try:
71
71
  completed_process = subprocess.run(
72
72
  ["git", "rev-parse", "--show-toplevel"],
73
- capture_output=True,
73
+ check=False, capture_output=True,
74
74
  text=True,
75
75
  timeout=GIT_COMMAND_TIMEOUT_SECONDS,
76
76
  cwd=str(Path(target_file).parent),
@@ -359,7 +359,7 @@ def run_mypy(target_file: str, project_root: str) -> tuple[int, str]:
359
359
 
360
360
  completed_process = subprocess.run(
361
361
  mypy_command,
362
- capture_output=True,
362
+ check=False, capture_output=True,
363
363
  text=True,
364
364
  env=os.environ.copy(),
365
365
  timeout=MYPY_TIMEOUT_SECONDS,
@@ -12,6 +12,7 @@ A library of check modules used by the validation hooks. Each module focuses on
12
12
  | `output_formatter.py` | Formats `Violation` lists into human-readable output |
13
13
  | `run_all_validators.py` | Entry point — runs every check module and aggregates results |
14
14
  | `health_check.py` | Verifies that all validator dependencies (ruff, mypy) are reachable |
15
+ | `python_style_helpers.py` | Shared source-line splitting and function-discovery helpers imported by `python_style_checks.py` |
15
16
 
16
17
  ## Check modules
17
18
 
@@ -33,7 +34,6 @@ A library of check modules used by the validation hooks. Each module focuses on
33
34
  | `todo_checks.py` | TODO/FIXME markers without an associated issue reference |
34
35
  | `type_safety_checks.py` | Type-safety rules (no `Any`, no `cast`, no `# type: ignore`) |
35
36
  | `useless_test_checks.py` | Tests that check only existence or constant values |
36
- | `verify_paths.py` | Validates that file paths referenced in code actually exist |
37
37
 
38
38
  ## Subdirectory
39
39
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  AST-based Python style checks for code quality enforcement.
4
4
 
5
+ The checks live in `python_style_checks.py`; the shared source-line splitting and function-discovery helpers they build on live in `python_style_helpers.py`.
6
+
5
7
  ## Checks Implemented
6
8
 
7
9
  1. **Imports at top** - All import statements must be at the top of the file
@@ -110,6 +110,7 @@ def check_optional_tool(tool_name: str) -> bool:
110
110
  try:
111
111
  result = subprocess.run(
112
112
  [tool_name, "--version"],
113
+ check=False,
113
114
  capture_output=True,
114
115
  text=True,
115
116
  )
@@ -18,6 +18,7 @@ def check_mypy_available() -> bool:
18
18
  try:
19
19
  result = subprocess.run(
20
20
  ["mypy", "--version"],
21
+ check=False,
21
22
  capture_output=True,
22
23
  text=True,
23
24
  )
@@ -85,6 +86,7 @@ def run_mypy_check(files: list[Path]) -> MypyResult:
85
86
  result = subprocess.run(
86
87
  ["mypy", *config_argument, "--ignore-missing-imports", "--no-error-summary"]
87
88
  + py_files,
89
+ check=False,
88
90
  capture_output=True,
89
91
  text=True,
90
92
  )