claude-dev-env 1.93.0 → 1.94.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 (220) hide show
  1. package/_shared/pr-loop/CLAUDE.md +1 -0
  2. package/_shared/pr-loop/audit-contract.md +1 -1
  3. package/_shared/pr-loop/gh-payloads.md +3 -3
  4. package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
  5. package/_shared/pr-loop/scripts/README.md +2 -2
  6. package/_shared/pr-loop/scripts/code_rules_gate.py +127 -13
  7. package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
  8. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +4 -0
  9. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +146 -69
  10. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
  11. package/_shared/pr-loop/state-schema.md +3 -22
  12. package/bin/CLAUDE.md +1 -1
  13. package/bin/install.mjs +2 -7
  14. package/bin/install.test.mjs +10 -4
  15. package/hooks/blocking/CLAUDE.md +2 -0
  16. package/hooks/blocking/pii_commit_command.py +398 -0
  17. package/hooks/blocking/pii_payload_scan.py +133 -0
  18. package/hooks/blocking/pii_prevention_blocker.py +151 -449
  19. package/hooks/blocking/pii_scanner.py +26 -1
  20. package/hooks/blocking/test_code_rules_enforcer_dead_config_field.py +2 -2
  21. package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
  22. package/hooks/blocking/test_pii_scanner.py +27 -2
  23. package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
  24. package/hooks/hooks_constants/CLAUDE.md +2 -2
  25. package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
  26. package/hooks/hooks_constants/local_identity.py +65 -15
  27. package/hooks/hooks_constants/pii_prevention_constants.py +20 -8
  28. package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
  29. package/hooks/hooks_constants/test_local_identity.py +68 -0
  30. package/package.json +1 -1
  31. package/scripts/CLAUDE.md +10 -1
  32. package/scripts/Get-SessionAccount.ps1 +210 -0
  33. package/scripts/tests/CLAUDE.md +15 -1
  34. package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
  35. package/skills/CLAUDE.md +3 -25
  36. package/skills/anthropic-plan/SKILL.md +1 -13
  37. package/skills/autoconverge/CLAUDE.md +5 -2
  38. package/skills/autoconverge/SKILL.md +112 -387
  39. package/skills/autoconverge/reference/CLAUDE.md +4 -1
  40. package/skills/autoconverge/reference/closing-report.md +9 -2
  41. package/skills/autoconverge/reference/convergence.md +26 -22
  42. package/skills/autoconverge/reference/headless-safety.md +44 -0
  43. package/skills/autoconverge/reference/multi-pr.md +88 -0
  44. package/skills/autoconverge/reference/self-closing-loop.md +84 -0
  45. package/skills/autoconverge/reference/stop-conditions.md +21 -13
  46. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
  47. package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
  48. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
  49. package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
  50. package/skills/autoconverge/workflow/converge.mjs +284 -94
  51. package/skills/bugteam/CLAUDE.md +1 -1
  52. package/skills/bugteam/CONSTRAINTS.md +3 -3
  53. package/skills/bugteam/PROMPTS.md +8 -19
  54. package/skills/bugteam/SKILL.md +13 -14
  55. package/skills/bugteam/reference/CLAUDE.md +1 -1
  56. package/skills/bugteam/reference/audit-and-teammates.md +2 -2
  57. package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
  58. package/skills/bugteam/reference/github-pr-reviews.md +56 -38
  59. package/skills/bugteam/reference/team-setup.md +11 -11
  60. package/skills/bugteam/scripts/CLAUDE.md +6 -6
  61. package/skills/bugteam/scripts/README.md +20 -8
  62. package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
  63. package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
  64. package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
  65. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
  66. package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
  67. package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
  68. package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
  69. package/skills/copilot-finding-triage/SKILL.md +80 -28
  70. package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
  71. package/skills/copilot-finding-triage/templates/notification.md +8 -3
  72. package/skills/everything-search/SKILL.md +1 -2
  73. package/skills/grokify/SKILL.md +58 -0
  74. package/skills/grokify/templates/handoff-template.md +92 -0
  75. package/skills/orchestrator/SKILL.md +12 -8
  76. package/skills/orchestrator-refresh/SKILL.md +3 -3
  77. package/skills/pr-converge/SKILL.md +132 -233
  78. package/skills/pr-converge/reference/convergence-gates.md +102 -66
  79. package/skills/pr-converge/reference/examples.md +37 -25
  80. package/skills/pr-converge/reference/fix-protocol.md +7 -7
  81. package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
  82. package/skills/pr-converge/reference/per-tick.md +64 -41
  83. package/skills/pr-converge/reference/state-schema.md +27 -2
  84. package/skills/pr-converge/scripts/CLAUDE.md +8 -0
  85. package/skills/pr-converge/scripts/README.md +4 -3
  86. package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
  87. package/skills/pr-converge/scripts/check_convergence.py +189 -645
  88. package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
  89. package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
  90. package/skills/pr-converge/scripts/conftest.py +8 -0
  91. package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
  92. package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
  93. package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
  94. package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
  95. package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
  96. package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
  97. package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
  98. package/skills/privacy-hygiene/SKILL.md +8 -7
  99. package/skills/reviewer-gates/SKILL.md +26 -8
  100. package/skills/session-log/SKILL.md +11 -12
  101. package/skills/session-tidy/SKILL.md +40 -30
  102. package/skills/skill-builder/CLAUDE.md +13 -10
  103. package/skills/skill-builder/SKILL.md +31 -31
  104. package/skills/skill-builder/references/CLAUDE.md +10 -6
  105. package/skills/skill-builder/references/delegation-map.md +13 -4
  106. package/skills/skill-builder/references/description-field.md +113 -0
  107. package/skills/skill-builder/references/self-audit-checklist.md +21 -4
  108. package/skills/skill-builder/references/skill-modularity.md +113 -0
  109. package/skills/skill-builder/references/skill-types.md +4 -0
  110. package/skills/skill-builder/templates/CLAUDE.md +4 -4
  111. package/skills/skill-builder/templates/gap-analysis.md +25 -1
  112. package/skills/skill-builder/workflows/CLAUDE.md +6 -4
  113. package/skills/skill-builder/workflows/improve-skill.md +17 -16
  114. package/skills/skill-builder/workflows/new-skill.md +34 -10
  115. package/skills/skill-builder/workflows/polish-skill.md +59 -43
  116. package/skills/usage-pause/SKILL.md +10 -14
  117. package/skills/bdd-protocol/CLAUDE.md +0 -26
  118. package/skills/bdd-protocol/SKILL.md +0 -30
  119. package/skills/bdd-protocol/references/CLAUDE.md +0 -10
  120. package/skills/bdd-protocol/references/anti-patterns.md +0 -26
  121. package/skills/bdd-protocol/references/example-mapping.md +0 -23
  122. package/skills/bg-agent/CLAUDE.md +0 -17
  123. package/skills/bg-agent/SKILL.md +0 -69
  124. package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
  125. package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
  126. package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
  127. package/skills/caveman/CLAUDE.md +0 -15
  128. package/skills/caveman/SKILL.md +0 -38
  129. package/skills/code/CLAUDE.md +0 -17
  130. package/skills/code/SKILL.md +0 -178
  131. package/skills/deep-research/CLAUDE.md +0 -17
  132. package/skills/deep-research/SKILL.md +0 -80
  133. package/skills/findbugs/CLAUDE.md +0 -20
  134. package/skills/findbugs/SKILL.md +0 -241
  135. package/skills/fixbugs/CLAUDE.md +0 -19
  136. package/skills/fixbugs/SKILL.md +0 -142
  137. package/skills/gh-paginate/CLAUDE.md +0 -18
  138. package/skills/gh-paginate/SKILL.md +0 -84
  139. package/skills/gotcha/CLAUDE.md +0 -33
  140. package/skills/gotcha/SKILL.md +0 -73
  141. package/skills/implement/CLAUDE.md +0 -27
  142. package/skills/implement/SKILL.md +0 -66
  143. package/skills/implement/scripts/CLAUDE.md +0 -22
  144. package/skills/implement/scripts/append_note.py +0 -133
  145. package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
  146. package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
  147. package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
  148. package/skills/implement/scripts/test_append_note.py +0 -191
  149. package/skills/log-audit/CLAUDE.md +0 -20
  150. package/skills/log-audit/SKILL.md +0 -66
  151. package/skills/log-audit/reference/CLAUDE.md +0 -9
  152. package/skills/log-audit/reference/charter.md +0 -52
  153. package/skills/log-audit/scripts/CLAUDE.md +0 -27
  154. package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
  155. package/skills/log-audit/scripts/collect_log_window.py +0 -199
  156. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
  157. package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
  158. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
  159. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
  160. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
  161. package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
  162. package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
  163. package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
  164. package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
  165. package/skills/logifix/CLAUDE.md +0 -36
  166. package/skills/logifix/SKILL.md +0 -69
  167. package/skills/logifix/scripts/CLAUDE.md +0 -16
  168. package/skills/logifix/scripts/logifix.ps1 +0 -205
  169. package/skills/monitor-open-prs/CLAUDE.md +0 -34
  170. package/skills/monitor-open-prs/SKILL.md +0 -88
  171. package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
  172. package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
  173. package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
  174. package/skills/monitor-open-prs/test_skill_contract.py +0 -27
  175. package/skills/post-audit-findings/SKILL.md +0 -80
  176. package/skills/pr-consistency-audit/CLAUDE.md +0 -34
  177. package/skills/pr-consistency-audit/SKILL.md +0 -116
  178. package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
  179. package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
  180. package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
  181. package/skills/pr-fix-protocol/SKILL.md +0 -65
  182. package/skills/pr-review-responder/CLAUDE.md +0 -35
  183. package/skills/pr-review-responder/EXAMPLES.md +0 -590
  184. package/skills/pr-review-responder/PRINCIPLES.md +0 -533
  185. package/skills/pr-review-responder/README.md +0 -168
  186. package/skills/pr-review-responder/SKILL.md +0 -203
  187. package/skills/pr-review-responder/TESTING.md +0 -350
  188. package/skills/pr-scope-resolve/SKILL.md +0 -45
  189. package/skills/pre-compact/CLAUDE.md +0 -24
  190. package/skills/pre-compact/SKILL.md +0 -134
  191. package/skills/qbug/CLAUDE.md +0 -40
  192. package/skills/qbug/SKILL.md +0 -387
  193. package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
  194. package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
  195. package/skills/refine/CLAUDE.md +0 -44
  196. package/skills/refine/SKILL.md +0 -262
  197. package/skills/refine/templates/CLAUDE.md +0 -17
  198. package/skills/refine/templates/implementation-notes-template.html +0 -56
  199. package/skills/refine/templates/plan-template.md +0 -60
  200. package/skills/research-mode/CLAUDE.md +0 -35
  201. package/skills/research-mode/SKILL.md +0 -53
  202. package/skills/structure-prompt/CLAUDE.md +0 -42
  203. package/skills/structure-prompt/SKILL.md +0 -44
  204. package/skills/structure-prompt/reference/CLAUDE.md +0 -28
  205. package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
  206. package/skills/structure-prompt/reference/block-classification.md +0 -27
  207. package/skills/structure-prompt/reference/canonical-case.md +0 -48
  208. package/skills/structure-prompt/reference/citation-depth.md +0 -70
  209. package/skills/structure-prompt/reference/cleanup.md +0 -33
  210. package/skills/structure-prompt/reference/constraints.md +0 -33
  211. package/skills/structure-prompt/reference/directives.md +0 -37
  212. package/skills/structure-prompt/reference/examples.md +0 -72
  213. package/skills/structure-prompt/reference/instantiation.md +0 -51
  214. package/skills/structure-prompt/reference/output-contract.md +0 -72
  215. package/skills/structure-prompt/reference/per-category.md +0 -23
  216. package/skills/structure-prompt/reference/persona.md +0 -38
  217. package/skills/structure-prompt/reference/research.md +0 -33
  218. package/skills/structure-prompt/reference/structure.md +0 -28
  219. package/skills/verified-build/CLAUDE.md +0 -33
  220. package/skills/verified-build/SKILL.md +0 -33
@@ -1,316 +1,41 @@
1
- """Tests for bugteam_preflight git hooks path verification.
1
+ """Smoke tests for the skill-path preflight wrap.
2
2
 
3
- Covers:
4
- - core.hooksPath unset: exits non-zero with correction message
5
- - core.hooksPath pointing to the correct claude hooks dir: exits zero
6
- - core.hooksPath pointing elsewhere (husky override): exits non-zero
7
- - core.hooksPath with trailing slash: must still pass after normalization
3
+ Behavioral coverage lives at
4
+ ``_shared/pr-loop/scripts/tests/test_preflight.py``.
8
5
  """
9
6
 
10
7
  from __future__ import annotations
11
8
 
12
9
  import importlib.util
13
- import subprocess
14
- import sys
15
10
  from pathlib import Path
16
11
  from types import ModuleType
17
- from unittest.mock import MagicMock, patch
18
12
 
19
- import pytest
20
13
 
21
-
22
- def _load_preflight_module() -> ModuleType:
14
+ def _load_wrap_module() -> ModuleType:
23
15
  module_path = Path(__file__).parent / "bugteam_preflight.py"
24
- spec = importlib.util.spec_from_file_location("bugteam_preflight", module_path)
25
- assert spec is not None
26
- assert spec.loader is not None
27
- module = importlib.util.module_from_spec(spec)
28
- spec.loader.exec_module(module)
29
- return module
30
-
31
-
32
- bugteam_preflight = _load_preflight_module()
33
-
34
-
35
- def _make_completed_process(
36
- stdout: str, returncode: int
37
- ) -> subprocess.CompletedProcess:
38
- process = MagicMock(spec=subprocess.CompletedProcess)
39
- process.stdout = stdout
40
- process.returncode = returncode
41
- return process
42
-
43
-
44
- def test_should_exit_nonzero_when_core_hooks_path_unset(capsys: pytest.CaptureFixture[str]) -> None:
45
- with patch("subprocess.run") as mock_run:
46
- mock_run.return_value = _make_completed_process("", returncode=1)
47
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
48
- assert exit_code != 0
49
- captured = capsys.readouterr()
50
- assert "core.hooksPath" in captured.err
51
- assert "npx claude-dev-env" in captured.err or "git config" in captured.err
52
-
53
-
54
- def test_should_exit_zero_when_core_hooks_path_points_to_claude_hooks(tmp_path: Path) -> None:
55
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
56
- claude_hooks_path.mkdir(parents=True)
57
- with patch("subprocess.run") as mock_run:
58
- mock_run.return_value = _make_completed_process(
59
- str(claude_hooks_path) + "\n", returncode=0
60
- )
61
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
62
- assert exit_code == 0
63
-
64
-
65
- def test_should_exit_nonzero_when_core_hooks_path_points_elsewhere(capsys: pytest.CaptureFixture[str]) -> None:
66
- with patch("subprocess.run") as mock_run:
67
- mock_run.return_value = _make_completed_process(
68
- "/some/other/path/.husky\n", returncode=0
69
- )
70
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
71
- assert exit_code != 0
72
- captured = capsys.readouterr()
73
- assert "core.hooksPath" in captured.err
74
-
75
-
76
- def test_should_include_correction_commands_in_error_message(capsys: pytest.CaptureFixture[str]) -> None:
77
- with patch("subprocess.run") as mock_run:
78
- mock_run.return_value = _make_completed_process("", returncode=1)
79
- bugteam_preflight.verify_git_hooks_path(Path("."))
80
- captured = capsys.readouterr()
81
- assert (
82
- "npx claude-dev-env" in captured.err
83
- or "git config --global core.hooksPath" in captured.err
84
- )
85
-
86
-
87
- def test_main_should_exit_nonzero_when_hooks_path_unset() -> None:
88
- with patch("subprocess.run") as mock_run:
89
- mock_run.return_value = _make_completed_process("", returncode=1)
90
- exit_code = bugteam_preflight.main(["--no-pytest"])
91
- assert exit_code != 0
92
-
93
-
94
- def test_main_should_continue_when_hooks_path_valid(tmp_path: Path) -> None:
95
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
96
- claude_hooks_path.mkdir(parents=True)
97
- with patch("subprocess.run") as mock_run:
98
- mock_run.return_value = _make_completed_process(
99
- str(claude_hooks_path) + "\n", returncode=0
100
- )
101
- exit_code = bugteam_preflight.main(["--no-pytest"])
102
- assert exit_code == 0
103
-
104
-
105
- def test_should_accept_hooks_path_with_trailing_slash() -> None:
106
- with patch("subprocess.run") as mock_run:
107
- mock_run.return_value = _make_completed_process(
108
- "/home/user/.claude/hooks/git-hooks/\n", returncode=0
109
- )
110
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
111
- assert exit_code == 0, (
112
- "hooksPath with trailing slash must pass verification after normalization"
113
- )
114
-
115
-
116
- def test_should_exit_zero_when_hooks_path_set_at_repo_scope(tmp_path: Path) -> None:
117
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
118
- claude_hooks_path.mkdir(parents=True)
119
- repo_root = tmp_path / "my-repo"
120
- repo_root.mkdir()
121
- with patch("subprocess.run") as mock_run:
122
- mock_run.return_value = _make_completed_process(
123
- str(claude_hooks_path) + "\n", returncode=0
124
- )
125
- exit_code = bugteam_preflight.verify_git_hooks_path(repo_root)
126
- assert exit_code == 0, (
127
- "verify_git_hooks_path must accept a valid path returned by effective "
128
- "config query (not restricted to --global scope)"
129
- )
130
- called_command = mock_run.call_args[0][0]
131
- assert "--global" not in called_command, (
132
- "verify_git_hooks_path must query effective config, not --global only"
133
- )
134
- assert "-C" in called_command, (
135
- "verify_git_hooks_path must use git -C <repo_root> for repo-effective config"
136
- )
137
- dash_c_index = called_command.index("-C")
138
- assert called_command[dash_c_index + 1] == str(repo_root), (
139
- "git -C must receive the resolved repository root path"
140
- )
141
-
142
-
143
- def test_verify_git_hooks_path_accepts_none_repository_root(tmp_path: Path) -> None:
144
- """When repository_root is None, the call must use git's cwd-effective config.
145
-
146
- Binds the documented optional contract: passing None must not raise and must
147
- omit the `-C <root>` arguments so git falls back to the working directory.
148
- """
149
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
150
- claude_hooks_path.mkdir(parents=True)
151
- with patch("subprocess.run") as mock_run:
152
- mock_run.return_value = _make_completed_process(
153
- str(claude_hooks_path) + "\n", returncode=0
154
- )
155
- exit_code = bugteam_preflight.verify_git_hooks_path(None)
156
- assert exit_code == 0
157
- called_command = mock_run.call_args[0][0]
158
- assert "-C" not in called_command, (
159
- "verify_git_hooks_path(None) must omit -C so git uses cwd-effective config"
160
- )
161
-
162
-
163
- def test_should_accept_hooks_path_with_backslash_and_trailing_slash() -> None:
164
- with patch("subprocess.run") as mock_run:
165
- mock_run.return_value = _make_completed_process(
166
- "C:\\Users\\user\\.claude\\hooks\\git-hooks\\\n", returncode=0
167
- )
168
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
169
- assert exit_code == 0, (
170
- "Windows hooksPath with trailing backslash must pass after normalization"
171
- )
172
-
173
-
174
- def test_should_exit_nonzero_when_git_executable_not_found(
175
- capsys: pytest.CaptureFixture[str],
176
- ) -> None:
177
- """Preflight must not crash with a traceback when git is missing from PATH."""
178
- with patch("subprocess.run", side_effect=FileNotFoundError()):
179
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
180
- assert exit_code != 0, (
181
- "FileNotFoundError from subprocess.run must produce a non-zero exit, "
182
- "not a propagated traceback"
183
- )
184
- captured = capsys.readouterr()
185
- assert "git" in captured.err.lower(), (
186
- "Error message must mention git so the user knows what is missing"
187
- )
188
- assert (
189
- "npx claude-dev-env" in captured.err
190
- or "git config --global core.hooksPath" in captured.err
191
- ), "Error message must include the enforcement-absent remediation hints"
192
-
193
-
194
- def test_should_exit_nonzero_when_subprocess_run_raises_os_error(
195
- capsys: pytest.CaptureFixture[str],
196
- ) -> None:
197
- """Preflight must surface a clean error for other OS-level git launch failures."""
198
- with patch("subprocess.run", side_effect=OSError("permission denied")):
199
- exit_code = bugteam_preflight.verify_git_hooks_path(Path("."))
200
- assert exit_code != 0, (
201
- "OSError from subprocess.run must produce a non-zero exit, "
202
- "not a propagated traceback"
203
- )
204
- captured = capsys.readouterr()
205
- assert "bugteam_preflight" in captured.err, (
206
- "Error message must be prefixed with the preflight tool name for context"
207
- )
208
- assert "permission denied" in captured.err, (
209
- "Error message must include the underlying OSError detail for diagnosis"
210
- )
211
-
212
-
213
- def test_has_pytest_configuration_finds_pytest_ini(tmp_path: Path) -> None:
214
- """has_pytest_configuration must detect pytest.ini at the repo root.
215
-
216
- Regression for loop1-17/loop1-18: the literals "pytest.ini",
217
- "pyproject.toml", and "[tool.pytest" were inlined in production function
218
- bodies; centralizing them in bugteam_scripts_constants and importing here
219
- pins the contract.
220
- """
221
- repository_root = tmp_path / "repo"
222
- repository_root.mkdir()
223
- (repository_root / "pytest.ini").write_text("[pytest]\n", encoding="utf-8")
224
- assert bugteam_preflight.has_pytest_configuration(repository_root) is True
225
-
226
-
227
- def test_has_pytest_configuration_finds_pyproject_pytest_section(
228
- tmp_path: Path,
229
- ) -> None:
230
- repository_root = tmp_path / "repo"
231
- repository_root.mkdir()
232
- (repository_root / "pyproject.toml").write_text(
233
- "[tool.pytest.ini_options]\nminversion = '6.0'\n", encoding="utf-8"
234
- )
235
- assert bugteam_preflight.has_pytest_configuration(repository_root) is True
236
-
237
-
238
- def test_has_pytest_configuration_returns_false_without_either_file(
239
- tmp_path: Path,
240
- ) -> None:
241
- repository_root = tmp_path / "repo"
242
- repository_root.mkdir()
243
- assert bugteam_preflight.has_pytest_configuration(repository_root) is False
244
-
245
-
246
- def test_main_should_halt_when_env_var_lists_bugteam(
247
- monkeypatch: pytest.MonkeyPatch,
248
- capsys: pytest.CaptureFixture[str],
249
- ) -> None:
250
- """CLAUDE_REVIEWS_DISABLED=bugteam must halt preflight with the dedicated exit code."""
251
- monkeypatch.setenv("CLAUDE_REVIEWS_DISABLED", "bugteam")
252
- monkeypatch.delenv("BUGTEAM_PREFLIGHT_SKIP", raising=False)
253
- exit_code = bugteam_preflight.main(["--no-pytest"])
254
- assert exit_code == bugteam_preflight.EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV
255
- captured = capsys.readouterr()
256
- assert "CLAUDE_REVIEWS_DISABLED" in captured.err
257
- assert "bugteam" in captured.err
258
-
259
-
260
- def test_main_should_continue_when_env_var_omits_bugteam(
261
- monkeypatch: pytest.MonkeyPatch,
262
- tmp_path: Path,
263
- ) -> None:
264
- """CLAUDE_REVIEWS_DISABLED without the bugteam token must not halt preflight."""
265
- monkeypatch.setenv("CLAUDE_REVIEWS_DISABLED", "copilot,bugbot")
266
- monkeypatch.delenv("BUGTEAM_PREFLIGHT_SKIP", raising=False)
267
- claude_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
268
- claude_hooks_path.mkdir(parents=True)
269
- with patch("subprocess.run") as mock_run:
270
- mock_run.return_value = _make_completed_process(
271
- str(claude_hooks_path) + "\n", returncode=0
272
- )
273
- exit_code = bugteam_preflight.main(["--no-pytest"])
274
- assert exit_code != bugteam_preflight.EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV
275
-
276
-
277
- def test_main_should_halt_when_env_var_contains_uppercase_or_whitespace_bugteam_token(
278
- monkeypatch: pytest.MonkeyPatch,
279
- ) -> None:
280
- """Token matching must be case-insensitive and whitespace-tolerant."""
281
- monkeypatch.setenv("CLAUDE_REVIEWS_DISABLED", " BugTeam , copilot ")
282
- monkeypatch.delenv("BUGTEAM_PREFLIGHT_SKIP", raising=False)
283
- exit_code = bugteam_preflight.main(["--no-pytest"])
284
- assert exit_code == bugteam_preflight.EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV
285
-
286
-
287
- def _was_called_with_argument(
288
- mock_subprocess_run: MagicMock, argument_token: str
289
- ) -> bool:
290
- return any(
291
- argument_token in each_call_args[0][0]
292
- for each_call_args in mock_subprocess_run.call_args_list
293
- )
294
-
295
-
296
- def test_verify_git_hooks_path_invokes_self_heal_before_effective_query(
297
- tmp_path: Path,
298
- ) -> None:
299
- """verify_git_hooks_path must delegate to the shared self-heal helper before --get."""
300
- canonical_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
301
- canonical_hooks_path.mkdir(parents=True)
302
- with patch("subprocess.run") as mock_run:
303
- mock_run.return_value = _make_completed_process(
304
- str(canonical_hooks_path) + "\n", returncode=0
305
- )
306
- bugteam_preflight.verify_git_hooks_path(tmp_path)
307
- assert _was_called_with_argument(mock_run, "--get-all"), (
308
- "verify_git_hooks_path must run the --local --get-all read for self-heal"
309
- )
310
- assert _was_called_with_argument(mock_run, "--get"), (
311
- "verify_git_hooks_path must still run the effective --get verification"
312
- )
313
- first_called_command = mock_run.call_args_list[0][0][0]
314
- assert "--get-all" in first_called_command, (
315
- "Self-heal must run BEFORE the effective config query, not after"
316
- )
16
+ specification = importlib.util.spec_from_file_location(
17
+ "bugteam_preflight",
18
+ module_path,
19
+ )
20
+ assert specification is not None
21
+ assert specification.loader is not None
22
+ wrap_module = importlib.util.module_from_spec(specification)
23
+ specification.loader.exec_module(wrap_module)
24
+ return wrap_module
25
+
26
+
27
+ def test_wrap_main_delegates_to_shared_module() -> None:
28
+ wrap_module = _load_wrap_module()
29
+ assert wrap_module.main.__module__ == "preflight"
30
+ shared_filename = Path(wrap_module.main.__code__.co_filename).name
31
+ assert shared_filename == "preflight.py"
32
+
33
+
34
+ def test_wrap_main_help_exits_cleanly() -> None:
35
+ wrap_module = _load_wrap_module()
36
+ try:
37
+ wrap_module.main(["--help"])
38
+ except SystemExit as exit_signal:
39
+ assert exit_signal.code in (0, None)
40
+ return
41
+ raise AssertionError("main(['--help']) must raise SystemExit")
@@ -1,19 +1,25 @@
1
1
  ---
2
2
  name: copilot-finding-triage
3
3
  description: >-
4
- Sorts each Copilot gate finding from a converge run into one of two tiers and
5
- routes it: a self-healing finding is auto-fixed, pushed, and counted toward
6
- convergence with no user page, while a code concern pages the user over ntfy
7
- and holds the run behind a 45-minute gate. Triggers: 'copilot finding triage',
8
- 'user review gate', 'tier copilot findings', 'triage the copilot gate'.
4
+ Sorts each Copilot gate finding from a converge run into one of two tiers, then
5
+ verifies each code concern with an executed check before routing it: a
6
+ self-healing finding is auto-fixed, pushed, and counted toward convergence with
7
+ no user page; a confirmed or refuted code concern is handled by the run with its
8
+ check evidence; only a code concern the check leaves inconclusive pages the user
9
+ over ntfy and holds the run behind a 45-minute gate. Triggers: 'copilot finding
10
+ triage', 'user review gate', 'tier copilot findings', 'triage the copilot gate'.
9
11
  ---
10
12
 
11
13
  # Copilot Finding Triage
12
14
 
13
- After a converge run's Copilot gate returns its findings, this skill sorts each
14
- one into a tier and acts on it. Findings scoped to style, type hints, or tests
15
- heal themselves inside the run. A logic, security, or behavior finding pages the user
16
- and holds the run until they answer or a 45-minute deadline passes.
15
+ After a converge run's Copilot gate returns its findings, this skill tiers each
16
+ one, verifies every code concern with an executed check, then acts on it.
17
+ Findings scoped to style, type hints, or tests heal themselves inside the run. A
18
+ logic, security, or behavior finding goes to a verifier that runs a check against
19
+ HEAD: a confirmed defect joins the fix round carrying its repro, a refuted claim
20
+ is answered on the thread with the check evidence, and only a finding the check
21
+ leaves inconclusive pages the user and holds the run until they answer or a
22
+ 45-minute deadline passes.
17
23
 
18
24
  ## When this applies
19
25
 
@@ -22,7 +28,6 @@ inside one of these callers:
22
28
 
23
29
  - `autoconverge` — the single-run converge workflow, at its Copilot wait-gate.
24
30
  - `pr-converge` — the looping converge workflow, at each Copilot tick.
25
- - `copilot-review` — the standalone Copilot babysitter.
26
31
 
27
32
  Each caller already fetches the review and carries a fix-and-push flow. This
28
33
  skill decides, per finding, whether that flow runs on its own or waits behind
@@ -40,12 +45,48 @@ Read the complete rubric in `reference/tier-rubric.md`. The short form:
40
45
  product decision. Logic or correctness defects, security, data handling,
41
46
  error-handling semantics, and concurrency.
42
47
 
43
- A finding that straddles both tiers sorts to CODE CONCERN. Any doubt routes to
44
- the user gate.
48
+ A finding that straddles both tiers sorts to CODE CONCERN. Any doubt about the
49
+ tier sorts the finding to CODE CONCERN.
50
+
51
+ ## The verification stage
52
+
53
+ Tiering names who might act; the verification stage between tiering and the user
54
+ gate settles it for every code concern. Each code-concern finding goes to its own
55
+ verifier agent, all in parallel, inside the run. The verifier runs a check
56
+ against the flagged HEAD and returns one of three verdicts.
57
+
58
+ **The governing rule: a verdict is conclusive only if an actual check was
59
+ executed.** Reading the source and reasoning about it, however sound, never
60
+ produces a conclusive verdict. A check is a concrete command the verifier runs
61
+ against the flagged HEAD — executing the code path with crafted inputs, forcing
62
+ the claimed error condition, or running a purpose-built test — whose captured
63
+ output demonstrates the behavior in question. Each verdict carries
64
+ `{verdict, checkCommand, checkOutput, evidence}`; a conclusive verdict whose
65
+ `checkCommand` or `checkOutput` is empty carries no executed check, so the run
66
+ downgrades it to inconclusive.
67
+
68
+ - **CONFIRMED** — the check reproduces the defect. The finding becomes
69
+ self-healing: it joins the fix round carrying its repro. The fix re-runs the
70
+ same repro check and shows it passes, adds the repro to the test suite as a
71
+ regression test where the suite covers that surface, lands in one commit and
72
+ pushes, replies to the thread with the fix SHA plus the before/after check
73
+ output, and resolves the thread. No page.
74
+ - **REFUTED** — the check shows the code already behaves correctly in the exact
75
+ scenario the finding claims is broken. The run replies to the thread with the
76
+ command(s) and captured output, resolves the thread, and counts the finding
77
+ clean. No page.
78
+ - **INCONCLUSIVE** — everything else: no runnable check exists, the check is
79
+ infeasible in this environment, the results are ambiguous, or the fix needs a
80
+ product decision between defensible behaviors. The verifier defaults to
81
+ inconclusive, and any doubt sorts here. These findings, and only these, flow
82
+ into the user gate.
83
+
84
+ A run with zero inconclusive findings never reaches the user gate.
45
85
 
46
86
  ## Self-healing flow
47
87
 
48
- A self-healing finding never pages the user.
88
+ A self-healing finding never pages the user. This covers a finding tiered
89
+ self-healing and a code concern the verifier confirmed.
49
90
 
50
91
  1. Fix the finding through the caller's existing fix flow.
51
92
  2. Verify the fix.
@@ -54,16 +95,18 @@ A self-healing finding never pages the user.
54
95
 
55
96
  ## User gate protocol
56
97
 
57
- Run this protocol when one or more CODE CONCERN findings sit on the round's HEAD.
98
+ Run this protocol when one or more code-concern findings stayed inconclusive
99
+ after verification on the round's HEAD.
58
100
 
59
101
  ### Step 1 — Page the user
60
102
 
61
103
  Run `scripts/notify_ntfy.py` with:
62
104
 
63
105
  - `--title` naming the PR.
64
- - `--message` summarizing each code-concern finding, one line each, as
65
- `file:line — severity — one sentence`. Build the body from
66
- `templates/notification.md`.
106
+ - `--message` summarizing each inconclusive finding, one line each, as
107
+ `file:line — severity — one sentence`, followed by the verifier's one-line
108
+ evidence note stating what check was attempted and why it was not decisive.
109
+ Build the body from `templates/notification.md`.
67
110
  - `--click-url` set to the Copilot review URL, so tapping the page opens the
68
111
  review.
69
112
 
@@ -82,17 +125,22 @@ moment the script exits zero.
82
125
  - If the deadline passes with no answer, run the caller's normal teardown and
83
126
  report the un-reviewed findings in the final report.
84
127
 
85
- ### Step 3 — Self-healing findings run in parallel
128
+ ### Step 3 — Self-healing and confirmed findings run in parallel
86
129
 
87
- Self-healing findings on the same HEAD do not wait for the gate. Fix, verify,
88
- commit, and push them through the caller's fix flow, and count the round toward
89
- convergence.
130
+ Self-healing findings and confirmed code concerns on the same HEAD do not wait
131
+ for the gate. Fix, verify, commit, and push them through the caller's fix flow,
132
+ and count the round toward convergence. A confirmed finding carries its repro, so
133
+ its fix re-runs that same check and posts the before/after output on the thread.
90
134
 
91
135
  ## Gate checklist
92
136
 
93
137
  - [ ] Every finding on HEAD carries a tier.
94
138
  - [ ] Each self-healing finding is fixed, verified, and pushed.
95
- - [ ] Each code-concern finding appears as one line in the ntfy body.
139
+ - [ ] Each code-concern finding carries a verifier verdict from an executed check.
140
+ - [ ] Each confirmed finding is fixed with its repro re-run and pushed.
141
+ - [ ] Each refuted finding's thread carries the check evidence and is resolved.
142
+ - [ ] Each inconclusive finding appears as one line in the ntfy body with its
143
+ evidence note.
96
144
  - [ ] The page carries the PR name, the per-finding summary, and the review URL.
97
145
  - [ ] `scripts/notify_ntfy.py` exited zero before the 45-minute clock started.
98
146
  - [ ] The wakeup is armed for 45 minutes from a delivered page.
@@ -102,9 +150,9 @@ convergence.
102
150
 
103
151
  | Path | Role |
104
152
  |------|------|
105
- | `SKILL.md` | This hub: when it applies, the tier split, the gate protocol. |
106
- | `reference/tier-rubric.md` | The complete tier rubric and the behavior-safe test. |
107
- | `templates/notification.md` | The ntfy message body for a code-concern page. |
153
+ | `SKILL.md` | This hub: when it applies, the tier split, the verification stage, the gate protocol. |
154
+ | `reference/tier-rubric.md` | The complete tier rubric, the three verdicts, and the executed-check standard. |
155
+ | `templates/notification.md` | The ntfy message body for an inconclusive-finding page. |
108
156
  | `scripts/notify_ntfy.py` | The ntfy publish CLI. |
109
157
  | `scripts/test_notify_ntfy.py` | Tests for the publish CLI. |
110
158
 
@@ -116,9 +164,13 @@ convergence.
116
164
  - **A failed page is not consent.** A failed ntfy POST holds the gate open. It
117
165
  does not auto-approve the round. Read the script's non-zero exit as a page that
118
166
  never reached the user, and keep the run held.
119
- - **Doubt sorts to CODE CONCERN.** When a finding could sit in either tier,
120
- classify it as a code concern and page the user. The safe default never
121
- auto-fixes a finding that might change runtime behavior.
167
+ - **A conclusive verdict needs an executed check.** Source reading, however
168
+ sound, never confirms or refutes a finding. A confirmed or refuted verdict
169
+ whose `checkCommand` or `checkOutput` is empty downgrades to inconclusive and
170
+ pages the user.
171
+ - **Doubt sorts to INCONCLUSIVE.** When an executed check does not pin down the
172
+ behavior, the verifier defaults to inconclusive and the finding pages the user.
173
+ The safe default never auto-fixes a finding whose behavior a check did not show.
122
174
  - **The 45-minute clock starts at page success.** The timer starts when the page
123
175
  reaches the user, which is the moment `scripts/notify_ntfy.py` exits zero, not
124
176
  the moment the finding is classified.
@@ -1,17 +1,19 @@
1
1
  # Tier Rubric
2
2
 
3
- Every Copilot finding on the round's HEAD sorts into one of two tiers. The tier
4
- decides who acts: the run fixes a self-healing finding on its own, and the run
5
- pages the user for a code concern.
3
+ Every Copilot finding on the round's HEAD passes through two stages: tiering,
4
+ then for a code concern an executed-check verification stage that decides who
5
+ acts. Tiering sorts a finding into one of two tiers. The run fixes a self-healing
6
+ finding on its own; a code concern goes to a verifier agent, and only a finding
7
+ the verifier leaves inconclusive pages the user.
6
8
 
7
9
  ## The two tiers
8
10
 
9
- | Tier | Who acts | Page the user | Counts toward convergence |
10
- |------|----------|---------------|---------------------------|
11
+ | Tier | Next step | Page the user | Counts toward convergence |
12
+ |------|-----------|---------------|---------------------------|
11
13
  | SELF-HEALING | The run auto-fixes | No | Yes |
12
- | CODE CONCERN | The user decides | Yes | Held until the user answers or the deadline passes |
14
+ | CODE CONCERN | An executed-check verifier decides | Only when the verifier's verdict is inconclusive | Confirmed and refuted count; inconclusive holds until the user answers or the deadline passes |
13
15
 
14
- ## The test that splits them
16
+ ## The test that splits the tiers
15
17
 
16
18
  A finding is SELF-HEALING when its fix cannot change what a production caller
17
19
  observes at runtime. A finding is a CODE CONCERN when its fix changes runtime
@@ -42,8 +44,65 @@ weigh a tradeoff.
42
44
  - Concurrency.
43
45
  - Anything whose fix changes observable production behavior.
44
46
 
45
- ## When a finding sits on the line
47
+ A finding that touches both tiers sorts to CODE CONCERN. Any doubt about the tier
48
+ sorts the finding to CODE CONCERN.
46
49
 
47
- A finding that touches both tiers sorts to CODE CONCERN. Any doubt about whether
48
- a fix stays behavior-safe routes the finding to the user gate. The safe default
49
- pages a person; it never auto-fixes a finding that might change runtime behavior.
50
+ ## The verification stage
51
+
52
+ Every code-concern finding goes to its own verifier agent, all in parallel,
53
+ inside the run. The verifier decides one of three verdicts by executing a check
54
+ against the flagged HEAD.
55
+
56
+ **The governing rule: a verdict is conclusive only if an actual check was
57
+ executed.** Reading the source and reasoning about it, however sound, never
58
+ produces a conclusive verdict. A check is a concrete command the verifier runs
59
+ against the flagged HEAD — executing the flagged code path with crafted inputs,
60
+ forcing the claimed error condition, or running a purpose-built test — whose
61
+ captured output demonstrates the behavior in question. Source inspection points
62
+ the check at the right place; it is never itself grounds for a conclusive verdict.
63
+
64
+ Each verdict carries `{verdict, checkCommand, checkOutput, evidence}`. A
65
+ conclusive verdict whose `checkCommand` or `checkOutput` is empty carries no
66
+ executed check, so the run downgrades it to inconclusive.
67
+
68
+ | Verdict | What the executed check shows | Who acts | Page the user |
69
+ |---------|-------------------------------|----------|---------------|
70
+ | CONFIRMED | The check tangibly reproduces the defect | The run auto-fixes | No |
71
+ | REFUTED | The check tangibly shows the code already behaves correctly in the exact scenario the finding claims is broken | The run replies and resolves | No |
72
+ | INCONCLUSIVE | Everything else | The user decides | Yes |
73
+
74
+ ### CONFIRMED
75
+
76
+ The executed check reproduces the defect; the evidence carries the exact
77
+ command(s) and the captured output. Only a confirmed verdict makes a
78
+ code-concern finding self-healing. The finding joins the round's fix list
79
+ carrying its repro, and the fix:
80
+
81
+ 1. Re-runs the same repro check and shows it passes.
82
+ 2. Adds the repro to the repo's test suite as a regression test where the suite
83
+ covers that surface.
84
+ 3. Lands in one commit and pushes.
85
+ 4. Replies to the thread with the fix SHA plus the before/after check output,
86
+ then resolves the thread.
87
+
88
+ The loop resumes on its own. No page.
89
+
90
+ ### REFUTED
91
+
92
+ The executed check demonstrates the code already behaves correctly in the exact
93
+ scenario the finding claims is broken. The run replies to the thread with the
94
+ command(s) and captured output, resolves the thread, and counts the finding
95
+ clean. No page.
96
+
97
+ ### INCONCLUSIVE
98
+
99
+ Everything else: no runnable check exists, the check is infeasible in this
100
+ environment, the results are ambiguous, or the fix needs a product decision
101
+ between defensible behaviors. A finding that is not tangibly reproducible is not
102
+ self-healing. These findings, and only these, flow into the user gate.
103
+
104
+ ## The default is inconclusive
105
+
106
+ The verifier defaults to inconclusive. Any doubt sorts to inconclusive, and an
107
+ inconclusive finding pages the user. The safe default pages a person; it never
108
+ auto-fixes a finding whose behavior an executed check did not pin down.
@@ -13,10 +13,12 @@ Copilot code concern on PR {pr_number}: {short_pr_title}
13
13
  ## Body
14
14
 
15
15
  ```
16
- {finding_count} code concern(s) need your call on PR {pr_number} ({head_sha}):
16
+ {finding_count} code concern(s) survived verification as inconclusive and need your call on PR {pr_number} ({head_sha}):
17
17
 
18
18
  - {file_1}:{line_1} — {severity_1} — {one_sentence_concern_1}
19
+ Check: {evidence_note_1}
19
20
  - {file_2}:{line_2} — {severity_2} — {one_sentence_concern_2}
21
+ Check: {evidence_note_2}
20
22
 
21
23
  Review: {review_url}
22
24
  Reply within 45 minutes or the run tears down and reports these findings unreviewed.
@@ -24,10 +26,13 @@ Reply within 45 minutes or the run tears down and reports these findings unrevie
24
26
 
25
27
  ## Field notes
26
28
 
27
- - `{finding_count}` counts the CODE CONCERN findings on this HEAD, not the
28
- self-healing ones.
29
+ - `{finding_count}` counts the inconclusive findings on this HEAD the code
30
+ concerns an executed check left undecided — not the self-healing, confirmed, or
31
+ refuted ones.
29
32
  - Each bullet holds one finding: its `file:line`, its severity, and one sentence
30
33
  naming the concern.
34
+ - `{evidence_note_N}` is the verifier's one-line note stating what check was
35
+ attempted and why it was not decisive.
31
36
  - `{review_url}` is the same URL passed as `--click-url`, so the reader sees it
32
37
  in the body and reaches it by tapping the message.
33
38
  - The 45-minute clock starts when the page reaches the user, which is the moment
@@ -13,8 +13,7 @@ Search files instantly on Windows using the Everything command-line interface (e
13
13
 
14
14
  ## Hard limits
15
15
 
16
- - **Scope every search.** Pass a project path, an `ext:`/`dm:`/`size:` filter, or a name pattern. A bare whole-drive scan or a network-share sweep is out of bounds.
17
- - **Fall back on failure.** When `es.exe` fails or returns nothing, try to start it. if that doesn't work, prompt the user to decide next steps: grep, debug further, etc.
16
+ Scope and fallback policy: `packages/claude-dev-env/rules/es-exe-file-search.md`.
18
17
 
19
18
  ## Instructions
20
19