claude-dev-env 1.58.0 → 1.60.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.
- package/CLAUDE.md +2 -2
- package/_shared/pr-loop/scripts/code_rules_gate.py +36 -3
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +6 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +1 -0
- package/_shared/pr-loop/scripts/reviews_disabled.py +12 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +265 -0
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +29 -0
- package/audit-rubrics/category_rubrics/category-b-selector-engine-compat.md +1 -1
- package/audit-rubrics/category_rubrics/category-e-dead-code.md +1 -0
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
- package/audit-rubrics/prompts/category-b-selector-engine-compat.md +2 -2
- package/bin/install.mjs +100 -27
- package/bin/install.test.mjs +133 -1
- package/docs/CODE_RULES.md +3 -3
- package/hooks/blocking/code_rules_annotations_length.py +153 -0
- package/hooks/blocking/code_rules_dead_dataclass_field.py +319 -0
- package/hooks/blocking/code_rules_dead_module_constant.py +321 -0
- package/hooks/blocking/code_rules_duplicate_body.py +439 -0
- package/hooks/blocking/code_rules_enforcer.py +190 -21
- package/hooks/blocking/code_rules_magic_values.py +98 -0
- package/hooks/blocking/code_rules_shared.py +41 -0
- package/hooks/blocking/code_rules_typeddict_stub.py +172 -0
- package/hooks/blocking/config/__init__.py +5 -0
- package/hooks/blocking/config/verified_commit_constants.py +106 -0
- package/hooks/blocking/destructive_command_blocker.py +1027 -12
- package/hooks/blocking/hook_prose_detector_consistency.py +150 -0
- package/hooks/blocking/subprocess_budget_completeness.py +380 -0
- package/hooks/blocking/test_code_rules_enforcer_annotations.py +225 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +1 -0
- package/hooks/blocking/test_code_rules_enforcer_cross_skill_duplicate.py +146 -0
- package/hooks/blocking/test_code_rules_enforcer_dead_dataclass_field.py +467 -0
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +188 -0
- package/hooks/blocking/test_code_rules_enforcer_duplicate_body.py +330 -0
- package/hooks/blocking/test_code_rules_enforcer_duplicate_body_hook_routing.py +179 -0
- package/hooks/blocking/test_code_rules_enforcer_magic_slice_bounds.py +133 -0
- package/hooks/blocking/test_code_rules_enforcer_zero_payload_alias.py +415 -0
- package/hooks/blocking/test_code_rules_enforcer_zero_payload_alias_hook_routing.py +156 -0
- package/hooks/blocking/test_destructive_command_blocker.py +622 -3
- package/hooks/blocking/test_hook_prose_detector_consistency.py +265 -0
- package/hooks/blocking/test_subprocess_budget_completeness.py +588 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +720 -0
- package/hooks/blocking/test_verification_verdict_store.py +278 -0
- package/hooks/blocking/test_verified_commit_gate.py +368 -0
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -0
- package/hooks/blocking/test_verifier_verdict_minter.py +214 -0
- package/hooks/blocking/test_workflow_substitution_slot_blocker.py +242 -0
- package/hooks/blocking/verdict_directory_write_blocker.py +667 -0
- package/hooks/blocking/verification_verdict_store.py +446 -0
- package/hooks/blocking/verified_commit_gate.py +523 -0
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +152 -0
- package/hooks/blocking/verifier_verdict_minter.py +299 -0
- package/hooks/blocking/workflow_substitution_slot_blocker.py +159 -0
- package/hooks/diagnostic/test_hook_log_extractor.py +3 -3
- package/hooks/hooks.json +58 -1
- package/hooks/hooks_constants/blocking_check_limits.py +1 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +16 -0
- package/hooks/hooks_constants/dead_dataclass_field_constants.py +25 -0
- package/hooks/hooks_constants/dead_module_constant_constants.py +20 -0
- package/hooks/hooks_constants/destructive_command_segment_constants.py +178 -0
- package/hooks/hooks_constants/duplicate_function_body_constants.py +34 -0
- package/hooks/hooks_constants/hook_prose_detector_consistency_constants.py +30 -0
- package/hooks/hooks_constants/precommit_code_rules_gate_constants.py +1 -1
- package/hooks/hooks_constants/subprocess_budget_completeness_constants.py +5 -0
- package/hooks/hooks_constants/workflow_substitution_slot_blocker_constants.py +22 -0
- package/package.json +1 -1
- package/rules/docstring-prose-matches-implementation.md +43 -0
- package/rules/file-global-constants.md +7 -1
- package/rules/hook-prose-matches-detector.md +26 -0
- package/rules/no-cross-skill-duplicate-helpers.md +29 -0
- package/rules/no-inline-destructive-literals.md +11 -0
- package/rules/workflow-substitution-slots.md +7 -0
- package/skills/_shared/pr-loop/scripts/preflight_worktree.py +392 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +70 -0
- package/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +263 -0
- package/skills/autoconverge/SKILL.md +67 -19
- package/skills/autoconverge/reference/closing-report.md +59 -17
- package/skills/autoconverge/reference/convergence.md +7 -3
- package/skills/autoconverge/reference/stop-conditions.md +7 -2
- package/skills/autoconverge/workflow/aggregate_runs.py +371 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +193 -76
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +76 -0
- package/skills/autoconverge/workflow/converge.contract.test.mjs +206 -206
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +265 -0
- package/skills/autoconverge/workflow/converge.mjs +234 -42
- package/skills/autoconverge/workflow/convergence_summary.py +110 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +2 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +7 -0
- package/skills/autoconverge/workflow/render_report.py +488 -397
- package/skills/autoconverge/workflow/test_aggregate_runs.py +134 -0
- package/skills/autoconverge/workflow/test_convergence_summary.py +132 -0
- package/skills/autoconverge/workflow/test_render_report.py +488 -259
- package/skills/pr-converge/reference/per-tick.md +28 -8
- package/skills/pr-converge/scripts/check_convergence.py +195 -64
- package/skills/pr-converge/scripts/test_check_convergence.py +173 -2
- package/skills/rebase/SKILL.md +2 -4
- package/skills/update/SKILL.md +37 -5
- package/system-prompts/software-engineer.xml +2 -6
- package/hooks/blocking/content_search_to_zoekt_redirector.py +0 -59
- package/hooks/blocking/content_search_zoekt_bash_block_reason.py +0 -25
- package/hooks/blocking/content_search_zoekt_block_payload.py +0 -21
- package/hooks/blocking/content_search_zoekt_indexed_paths.py +0 -24
- package/hooks/blocking/content_search_zoekt_indexed_roots_config.py +0 -131
- package/hooks/blocking/content_search_zoekt_redirect_guidance.py +0 -52
- package/hooks/blocking/test_content_search_to_zoekt_redirector_integration.py +0 -61
- package/hooks/blocking/test_content_search_to_zoekt_redirector_unit.py +0 -92
- package/hooks/blocking/test_content_search_zoekt_indexed_roots_config.py +0 -102
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"""Tests for cross-file duplicate top-level function body detection.
|
|
2
|
+
|
|
3
|
+
PR #567 added the 5th and 6th copies of a byte-identical ``strip_code_and_quotes``
|
|
4
|
+
helper across sibling Stop-hook modules. This check blocks that violation class at
|
|
5
|
+
Write time: a top-level function whose body matches a top-level function in a
|
|
6
|
+
sibling ``.py`` module in the same directory is flagged so the author extracts one
|
|
7
|
+
shared helper instead of copying it.
|
|
8
|
+
|
|
9
|
+
The tests write real sibling files into a neutrally named temporary directory and
|
|
10
|
+
run the check against them, so they exercise the on-disk directory scan rather
|
|
11
|
+
than a stubbed view of the filesystem. The directory is named like a production
|
|
12
|
+
package directory (no ``test_`` segment), because the check treats any path
|
|
13
|
+
containing a test marker as exempt — the same way it would skip a real test file.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import importlib.util
|
|
19
|
+
import pathlib
|
|
20
|
+
import shutil
|
|
21
|
+
import sys
|
|
22
|
+
import tempfile
|
|
23
|
+
from collections.abc import Iterator
|
|
24
|
+
|
|
25
|
+
import pytest
|
|
26
|
+
|
|
27
|
+
_HOOK_DIRECTORY = pathlib.Path(__file__).parent
|
|
28
|
+
if str(_HOOK_DIRECTORY) not in sys.path:
|
|
29
|
+
sys.path.insert(0, str(_HOOK_DIRECTORY))
|
|
30
|
+
|
|
31
|
+
_hook_spec = importlib.util.spec_from_file_location(
|
|
32
|
+
"code_rules_enforcer",
|
|
33
|
+
_HOOK_DIRECTORY / "code_rules_enforcer.py",
|
|
34
|
+
)
|
|
35
|
+
assert _hook_spec is not None
|
|
36
|
+
assert _hook_spec.loader is not None
|
|
37
|
+
_hook_module = importlib.util.module_from_spec(_hook_spec)
|
|
38
|
+
_hook_spec.loader.exec_module(_hook_module)
|
|
39
|
+
check_duplicate_function_body_across_files = _hook_module.check_duplicate_function_body_across_files
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
SHARED_HELPER_SOURCE = (
|
|
43
|
+
"import re\n"
|
|
44
|
+
"\n"
|
|
45
|
+
"def strip_code_and_quotes(text: str) -> str:\n"
|
|
46
|
+
" without_fences = re.sub(r'```.*?```', '', text, flags=re.DOTALL)\n"
|
|
47
|
+
" without_inline = re.sub(r'`[^`]*`', '', without_fences)\n"
|
|
48
|
+
" without_quotes = re.sub(r'(?m)^>.*$', '', without_inline)\n"
|
|
49
|
+
" return without_quotes.strip()\n"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.fixture
|
|
54
|
+
def module_dir() -> Iterator[pathlib.Path]:
|
|
55
|
+
base_directory = pathlib.Path(tempfile.mkdtemp())
|
|
56
|
+
package_directory = base_directory / "blocking"
|
|
57
|
+
package_directory.mkdir()
|
|
58
|
+
try:
|
|
59
|
+
yield package_directory
|
|
60
|
+
finally:
|
|
61
|
+
shutil.rmtree(base_directory, ignore_errors=False)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _write(directory: pathlib.Path, name: str, source: str) -> pathlib.Path:
|
|
65
|
+
target = directory / name
|
|
66
|
+
target.write_text(source, encoding="utf-8")
|
|
67
|
+
return target
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_should_flag_function_copied_from_sibling(module_dir: pathlib.Path) -> None:
|
|
71
|
+
_write(module_dir, "existing_blocker.py", SHARED_HELPER_SOURCE)
|
|
72
|
+
new_file = module_dir / "new_blocker.py"
|
|
73
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(new_file))
|
|
74
|
+
assert any("strip_code_and_quotes" in each_issue for each_issue in issues), (
|
|
75
|
+
f"Expected the copied helper to be flagged, got: {issues}"
|
|
76
|
+
)
|
|
77
|
+
assert any("existing_blocker.py" in each_issue for each_issue in issues), (
|
|
78
|
+
f"Expected the sibling source location named, got: {issues}"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_should_not_flag_when_no_sibling_matches(module_dir: pathlib.Path) -> None:
|
|
83
|
+
_write(
|
|
84
|
+
module_dir,
|
|
85
|
+
"unrelated.py",
|
|
86
|
+
"def add(left: int, right: int) -> int:\n"
|
|
87
|
+
" total = left + right\n"
|
|
88
|
+
" doubled = total * 2\n"
|
|
89
|
+
" return doubled\n",
|
|
90
|
+
)
|
|
91
|
+
new_file = module_dir / "new_blocker.py"
|
|
92
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(new_file))
|
|
93
|
+
assert issues == [], f"No matching sibling body must not flag, got: {issues}"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_should_not_flag_trivial_short_body(module_dir: pathlib.Path) -> None:
|
|
97
|
+
trivial_source = "def noop() -> None:\n return None\n"
|
|
98
|
+
_write(module_dir, "existing.py", trivial_source)
|
|
99
|
+
new_file = module_dir / "new.py"
|
|
100
|
+
issues = check_duplicate_function_body_across_files(trivial_source, str(new_file))
|
|
101
|
+
assert issues == [], (
|
|
102
|
+
f"A body under the minimum statement count is too common to flag, got: {issues}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_should_ignore_docstring_only_difference(module_dir: pathlib.Path) -> None:
|
|
107
|
+
with_docstring = (
|
|
108
|
+
"def compute(left: int, right: int) -> int:\n"
|
|
109
|
+
' """Add then scale."""\n'
|
|
110
|
+
" total = left + right\n"
|
|
111
|
+
" scaled = total * 3\n"
|
|
112
|
+
" return scaled\n"
|
|
113
|
+
)
|
|
114
|
+
without_docstring = (
|
|
115
|
+
"def compute(left: int, right: int) -> int:\n"
|
|
116
|
+
" total = left + right\n"
|
|
117
|
+
" scaled = total * 3\n"
|
|
118
|
+
" return scaled\n"
|
|
119
|
+
)
|
|
120
|
+
_write(module_dir, "existing.py", with_docstring)
|
|
121
|
+
new_file = module_dir / "new.py"
|
|
122
|
+
issues = check_duplicate_function_body_across_files(without_docstring, str(new_file))
|
|
123
|
+
assert any("compute" in each_issue for each_issue in issues), (
|
|
124
|
+
f"A docstring-only difference must not hide the duplicate, got: {issues}"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_should_skip_test_file_being_written(module_dir: pathlib.Path) -> None:
|
|
129
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
130
|
+
test_file = module_dir / "test_new.py"
|
|
131
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(test_file))
|
|
132
|
+
assert issues == [], f"Test files are exempt on the writing side, got: {issues}"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_should_skip_test_file_siblings(module_dir: pathlib.Path) -> None:
|
|
136
|
+
_write(module_dir, "test_existing.py", SHARED_HELPER_SOURCE)
|
|
137
|
+
new_file = module_dir / "new_blocker.py"
|
|
138
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(new_file))
|
|
139
|
+
assert issues == [], (
|
|
140
|
+
f"A matching body in a sibling test file must not flag production code, got: {issues}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_should_skip_dunder_init_being_written(module_dir: pathlib.Path) -> None:
|
|
145
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
146
|
+
init_file = module_dir / "__init__.py"
|
|
147
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(init_file))
|
|
148
|
+
assert issues == [], f"__init__.py re-export surfaces are exempt, got: {issues}"
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_should_not_compare_against_self(module_dir: pathlib.Path) -> None:
|
|
152
|
+
existing = _write(module_dir, "blocker.py", SHARED_HELPER_SOURCE)
|
|
153
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(existing))
|
|
154
|
+
assert issues == [], (
|
|
155
|
+
f"A file must not be flagged as a duplicate of its own on-disk copy, got: {issues}"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_should_return_empty_on_syntax_error(module_dir: pathlib.Path) -> None:
|
|
160
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
161
|
+
new_file = module_dir / "broken.py"
|
|
162
|
+
issues = check_duplicate_function_body_across_files("def broken(\n", str(new_file))
|
|
163
|
+
assert issues == [], f"Unparseable content must return empty, got: {issues}"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_should_skip_unparseable_sibling(module_dir: pathlib.Path) -> None:
|
|
167
|
+
_write(module_dir, "broken_sibling.py", "def broken(\n")
|
|
168
|
+
_write(module_dir, "good_sibling.py", SHARED_HELPER_SOURCE)
|
|
169
|
+
new_file = module_dir / "new.py"
|
|
170
|
+
issues = check_duplicate_function_body_across_files(SHARED_HELPER_SOURCE, str(new_file))
|
|
171
|
+
assert any("good_sibling.py" in each_issue for each_issue in issues), (
|
|
172
|
+
f"A broken sibling must be skipped without hiding a real match, got: {issues}"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_should_not_flag_method_inside_class(module_dir: pathlib.Path) -> None:
|
|
177
|
+
class_source = (
|
|
178
|
+
"class Worker:\n"
|
|
179
|
+
" def run(self, left: int, right: int) -> int:\n"
|
|
180
|
+
" total = left + right\n"
|
|
181
|
+
" scaled = total * 4\n"
|
|
182
|
+
" return scaled\n"
|
|
183
|
+
)
|
|
184
|
+
_write(module_dir, "existing.py", class_source)
|
|
185
|
+
new_file = module_dir / "new.py"
|
|
186
|
+
issues = check_duplicate_function_body_across_files(class_source, str(new_file))
|
|
187
|
+
assert issues == [], f"Only module-scope functions are compared, not methods, got: {issues}"
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
_UNRELATED_LEADING_FUNCTION = (
|
|
191
|
+
"def unrelated_helper(left: int, right: int) -> int:\n"
|
|
192
|
+
" summed = left + right\n"
|
|
193
|
+
" tripled = summed * 3\n"
|
|
194
|
+
" return tripled\n"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_should_not_flag_when_edit_leaves_duplicate_outside_changed_lines(
|
|
199
|
+
module_dir: pathlib.Path,
|
|
200
|
+
) -> None:
|
|
201
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
202
|
+
new_file = module_dir / "new_blocker.py"
|
|
203
|
+
post_edit_content = _UNRELATED_LEADING_FUNCTION + "\n\n" + SHARED_HELPER_SOURCE
|
|
204
|
+
changed_lines_outside_duplicate = {1, 2, 3, 4}
|
|
205
|
+
issues = check_duplicate_function_body_across_files(
|
|
206
|
+
post_edit_content,
|
|
207
|
+
str(new_file),
|
|
208
|
+
all_changed_lines=changed_lines_outside_duplicate,
|
|
209
|
+
)
|
|
210
|
+
assert issues == [], (
|
|
211
|
+
"An Edit that never touches the duplicated function must not block, "
|
|
212
|
+
f"got: {issues}"
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def test_should_flag_when_edit_changed_lines_intersect_duplicate(
|
|
217
|
+
module_dir: pathlib.Path,
|
|
218
|
+
) -> None:
|
|
219
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
220
|
+
new_file = module_dir / "new_blocker.py"
|
|
221
|
+
post_edit_content = _UNRELATED_LEADING_FUNCTION + "\n\n" + SHARED_HELPER_SOURCE
|
|
222
|
+
duplicate_definition_line = post_edit_content.splitlines().index(
|
|
223
|
+
"def strip_code_and_quotes(text: str) -> str:"
|
|
224
|
+
) + 1
|
|
225
|
+
changed_lines_inside_duplicate = {duplicate_definition_line + 1}
|
|
226
|
+
issues = check_duplicate_function_body_across_files(
|
|
227
|
+
post_edit_content,
|
|
228
|
+
str(new_file),
|
|
229
|
+
all_changed_lines=changed_lines_inside_duplicate,
|
|
230
|
+
)
|
|
231
|
+
assert any("strip_code_and_quotes" in each_issue for each_issue in issues), (
|
|
232
|
+
"An Edit whose changed lines touch the copied helper must still flag, "
|
|
233
|
+
f"got: {issues}"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def test_should_flag_whole_file_write_when_changed_lines_is_none(
|
|
238
|
+
module_dir: pathlib.Path,
|
|
239
|
+
) -> None:
|
|
240
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
241
|
+
new_file = module_dir / "new_blocker.py"
|
|
242
|
+
issues = check_duplicate_function_body_across_files(
|
|
243
|
+
SHARED_HELPER_SOURCE,
|
|
244
|
+
str(new_file),
|
|
245
|
+
all_changed_lines=None,
|
|
246
|
+
)
|
|
247
|
+
assert any("strip_code_and_quotes" in each_issue for each_issue in issues), (
|
|
248
|
+
"A whole-file Write treats every line as in scope and must flag, "
|
|
249
|
+
f"got: {issues}"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_should_scan_explicit_sibling_directory_for_relative_path(
|
|
254
|
+
module_dir: pathlib.Path,
|
|
255
|
+
) -> None:
|
|
256
|
+
_write(module_dir, "existing_blocker.py", SHARED_HELPER_SOURCE)
|
|
257
|
+
issues = check_duplicate_function_body_across_files(
|
|
258
|
+
SHARED_HELPER_SOURCE,
|
|
259
|
+
"package/new_blocker.py",
|
|
260
|
+
sibling_directory=module_dir,
|
|
261
|
+
)
|
|
262
|
+
assert any("strip_code_and_quotes" in each_issue for each_issue in issues), (
|
|
263
|
+
"When given an explicit sibling directory, the check must scan it for a "
|
|
264
|
+
f"relative file_path rather than the path's CWD-relative parent, got: {issues}"
|
|
265
|
+
)
|
|
266
|
+
assert any("existing_blocker.py" in each_issue for each_issue in issues), (
|
|
267
|
+
f"Expected the sibling source location named, got: {issues}"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def test_should_ignore_cwd_when_explicit_sibling_directory_given(
|
|
272
|
+
module_dir: pathlib.Path,
|
|
273
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
274
|
+
) -> None:
|
|
275
|
+
_write(module_dir, "existing_blocker.py", SHARED_HELPER_SOURCE)
|
|
276
|
+
monkeypatch.chdir(module_dir.parent)
|
|
277
|
+
issues = check_duplicate_function_body_across_files(
|
|
278
|
+
SHARED_HELPER_SOURCE,
|
|
279
|
+
"package/new_blocker.py",
|
|
280
|
+
sibling_directory=module_dir,
|
|
281
|
+
)
|
|
282
|
+
assert any("strip_code_and_quotes" in each_issue for each_issue in issues), (
|
|
283
|
+
"An explicit sibling directory must anchor the scan independent of the "
|
|
284
|
+
f"process working directory, got: {issues}"
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def test_should_return_every_violation_when_scope_deferred_to_caller(
|
|
289
|
+
module_dir: pathlib.Path,
|
|
290
|
+
) -> None:
|
|
291
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
292
|
+
new_file = module_dir / "new_blocker.py"
|
|
293
|
+
post_edit_content = _UNRELATED_LEADING_FUNCTION + "\n\n" + SHARED_HELPER_SOURCE
|
|
294
|
+
changed_lines_outside_duplicate = {1, 2, 3, 4}
|
|
295
|
+
issues = check_duplicate_function_body_across_files(
|
|
296
|
+
post_edit_content,
|
|
297
|
+
str(new_file),
|
|
298
|
+
all_changed_lines=changed_lines_outside_duplicate,
|
|
299
|
+
defer_scope_to_caller=True,
|
|
300
|
+
)
|
|
301
|
+
assert any("strip_code_and_quotes" in each_issue for each_issue in issues), (
|
|
302
|
+
"The commit/push gate scopes by added line, so the check must return "
|
|
303
|
+
f"every violation when scope is deferred, got: {issues}"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def test_should_carry_a_parseable_span_for_the_commit_gate_scoper(
|
|
308
|
+
module_dir: pathlib.Path,
|
|
309
|
+
) -> None:
|
|
310
|
+
_write(module_dir, "existing.py", SHARED_HELPER_SOURCE)
|
|
311
|
+
new_file = module_dir / "new_blocker.py"
|
|
312
|
+
post_edit_content = _UNRELATED_LEADING_FUNCTION + "\n\n" + SHARED_HELPER_SOURCE
|
|
313
|
+
duplicate_definition_line = post_edit_content.splitlines().index(
|
|
314
|
+
"def strip_code_and_quotes(text: str) -> str:"
|
|
315
|
+
) + 1
|
|
316
|
+
issues = check_duplicate_function_body_across_files(
|
|
317
|
+
post_edit_content,
|
|
318
|
+
str(new_file),
|
|
319
|
+
all_changed_lines=None,
|
|
320
|
+
defer_scope_to_caller=True,
|
|
321
|
+
)
|
|
322
|
+
matching_issues = [
|
|
323
|
+
each_issue for each_issue in issues if "strip_code_and_quotes" in each_issue
|
|
324
|
+
]
|
|
325
|
+
assert matching_issues, f"expected a duplicate-body issue, got: {issues}"
|
|
326
|
+
expected_fragment = f"(duplicate body span at line {duplicate_definition_line}, spanning 5 lines)"
|
|
327
|
+
assert expected_fragment in matching_issues[0], (
|
|
328
|
+
"The commit gate's scope splitter parses the copied function's span from "
|
|
329
|
+
f"the message, so the message must carry it, got: {matching_issues[0]}"
|
|
330
|
+
)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Entry-point tests proving the duplicate-body check guards hook-infrastructure files.
|
|
2
|
+
|
|
3
|
+
The cross-file duplicate-body check exists to catch a helper copied across sibling
|
|
4
|
+
modules in the ``blocking/`` hook directory itself — the exact directory the rest of
|
|
5
|
+
the code-rules suite exempts. These tests drive the real entry points (the ``main()``
|
|
6
|
+
stdin path and the pre-check CLI) with a hook-infrastructure target so the deny fires
|
|
7
|
+
on the same path a live Write would take, rather than calling the check function
|
|
8
|
+
directly.
|
|
9
|
+
|
|
10
|
+
Each test builds a temporary tree whose tail mirrors a production hook directory
|
|
11
|
+
(``packages/claude-dev-env/hooks/blocking``) so ``is_hook_infrastructure`` matches the
|
|
12
|
+
target path the same way it would for the real directory.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import io
|
|
18
|
+
import json
|
|
19
|
+
import pathlib
|
|
20
|
+
import shutil
|
|
21
|
+
import subprocess
|
|
22
|
+
import sys
|
|
23
|
+
import tempfile
|
|
24
|
+
from collections.abc import Iterator
|
|
25
|
+
from types import SimpleNamespace
|
|
26
|
+
|
|
27
|
+
import pytest
|
|
28
|
+
|
|
29
|
+
_HOOK_DIRECTORY = pathlib.Path(__file__).resolve().parent
|
|
30
|
+
_HOOKS_PARENT = _HOOK_DIRECTORY.parent
|
|
31
|
+
if str(_HOOK_DIRECTORY) not in sys.path:
|
|
32
|
+
sys.path.insert(0, str(_HOOK_DIRECTORY))
|
|
33
|
+
if str(_HOOKS_PARENT) not in sys.path:
|
|
34
|
+
sys.path.insert(0, str(_HOOKS_PARENT))
|
|
35
|
+
|
|
36
|
+
from code_rules_enforcer import main # noqa: E402
|
|
37
|
+
|
|
38
|
+
code_rules_enforcer = SimpleNamespace(main=main, sys=sys)
|
|
39
|
+
|
|
40
|
+
_ENFORCER_SCRIPT_PATH = _HOOK_DIRECTORY / "code_rules_enforcer.py"
|
|
41
|
+
|
|
42
|
+
SHARED_HELPER_SOURCE = (
|
|
43
|
+
"import re\n"
|
|
44
|
+
"\n"
|
|
45
|
+
"def strip_code_and_quotes(text: str) -> str:\n"
|
|
46
|
+
" without_fences = re.sub(r'```.*?```', '', text, flags=re.DOTALL)\n"
|
|
47
|
+
" without_inline = re.sub(r'`[^`]*`', '', without_fences)\n"
|
|
48
|
+
" without_quotes = re.sub(r'(?m)^>.*$', '', without_inline)\n"
|
|
49
|
+
" return without_quotes.strip()\n"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
_HOOK_INFRASTRUCTURE_TAIL = pathlib.Path("packages") / "claude-dev-env" / "hooks" / "blocking"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.fixture
|
|
56
|
+
def hook_blocking_dir() -> Iterator[pathlib.Path]:
|
|
57
|
+
base_directory = pathlib.Path(tempfile.mkdtemp())
|
|
58
|
+
blocking_directory = base_directory / _HOOK_INFRASTRUCTURE_TAIL
|
|
59
|
+
blocking_directory.mkdir(parents=True)
|
|
60
|
+
try:
|
|
61
|
+
yield blocking_directory
|
|
62
|
+
finally:
|
|
63
|
+
shutil.rmtree(base_directory, ignore_errors=False)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _run_main_with_write_payload(
|
|
67
|
+
file_path: str,
|
|
68
|
+
content: str,
|
|
69
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
70
|
+
capsys: pytest.CaptureFixture[str],
|
|
71
|
+
) -> str:
|
|
72
|
+
"""Drive ``main()`` through its stdin entry point for a Write and return stdout.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
file_path: The on-disk path the Write targets.
|
|
76
|
+
content: The whole-file body the Write would create.
|
|
77
|
+
monkeypatch: The fixture used to redirect ``sys.stdin``.
|
|
78
|
+
capsys: The fixture used to capture the deny payload on stdout.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
The captured stdout, which holds the deny payload when violations fire.
|
|
82
|
+
"""
|
|
83
|
+
write_payload = json.dumps(
|
|
84
|
+
{
|
|
85
|
+
"tool_name": "Write",
|
|
86
|
+
"tool_input": {"file_path": file_path, "content": content},
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
monkeypatch.setattr(code_rules_enforcer.sys, "stdin", io.StringIO(write_payload))
|
|
90
|
+
try:
|
|
91
|
+
code_rules_enforcer.main([])
|
|
92
|
+
except SystemExit:
|
|
93
|
+
pass
|
|
94
|
+
return capsys.readouterr().out
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_write_of_copied_helper_into_hook_directory_denies(
|
|
98
|
+
hook_blocking_dir: pathlib.Path,
|
|
99
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
100
|
+
capsys: pytest.CaptureFixture[str],
|
|
101
|
+
) -> None:
|
|
102
|
+
"""A Write that copies a sibling helper into a second hook file is denied.
|
|
103
|
+
|
|
104
|
+
The target lives under a hook-infrastructure path the rest of the code-rules
|
|
105
|
+
suite exempts, so this proves the duplicate-body check still guards the exact
|
|
106
|
+
directory its module docstring names as the primary target."""
|
|
107
|
+
(hook_blocking_dir / "existing_blocker.py").write_text(SHARED_HELPER_SOURCE, encoding="utf-8")
|
|
108
|
+
new_file = hook_blocking_dir / "new_blocker.py"
|
|
109
|
+
stdout = _run_main_with_write_payload(str(new_file), SHARED_HELPER_SOURCE, monkeypatch, capsys)
|
|
110
|
+
assert stdout != "", (
|
|
111
|
+
"A copied helper written into a second hook-infrastructure file must "
|
|
112
|
+
"produce a deny payload, got empty stdout"
|
|
113
|
+
)
|
|
114
|
+
deny_payload = json.loads(stdout)
|
|
115
|
+
decision = deny_payload["hookSpecificOutput"]["permissionDecision"]
|
|
116
|
+
reason = deny_payload["hookSpecificOutput"]["permissionDecisionReason"]
|
|
117
|
+
assert decision == "deny", f"expected deny, got: {decision!r}"
|
|
118
|
+
assert "strip_code_and_quotes" in reason, (
|
|
119
|
+
f"the deny reason must name the duplicated helper, got: {reason!r}"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_write_of_unique_helper_into_hook_directory_allows(
|
|
124
|
+
hook_blocking_dir: pathlib.Path,
|
|
125
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
126
|
+
capsys: pytest.CaptureFixture[str],
|
|
127
|
+
) -> None:
|
|
128
|
+
"""A Write of a hook file with no sibling duplicate produces no deny payload.
|
|
129
|
+
|
|
130
|
+
Routing hook ``.py`` files to the duplicate-body check must not block a hook
|
|
131
|
+
file that introduces a genuinely new helper; only a copied body denies."""
|
|
132
|
+
(hook_blocking_dir / "existing_blocker.py").write_text(SHARED_HELPER_SOURCE, encoding="utf-8")
|
|
133
|
+
unique_helper_source = (
|
|
134
|
+
"def normalize_indices(left: int, right: int) -> int:\n"
|
|
135
|
+
" combined = left + right\n"
|
|
136
|
+
" widened = combined * 5\n"
|
|
137
|
+
" return widened\n"
|
|
138
|
+
)
|
|
139
|
+
new_file = hook_blocking_dir / "unique_blocker.py"
|
|
140
|
+
stdout = _run_main_with_write_payload(str(new_file), unique_helper_source, monkeypatch, capsys)
|
|
141
|
+
assert stdout == "", f"a unique hook helper must not be denied, got stdout: {stdout!r}"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_precheck_of_copied_helper_at_hook_target_exits_nonzero(
|
|
145
|
+
hook_blocking_dir: pathlib.Path,
|
|
146
|
+
tmp_path_factory: pytest.TempPathFactory,
|
|
147
|
+
) -> None:
|
|
148
|
+
"""The pre-check CLI flags a copied helper judged at a hook-infrastructure target.
|
|
149
|
+
|
|
150
|
+
Driving the real ``--check`` argv path proves the gate's pre-check mode also
|
|
151
|
+
routes a hook ``.py`` target through the duplicate-body check rather than
|
|
152
|
+
exiting clean on the blanket hook-infrastructure exemption."""
|
|
153
|
+
(hook_blocking_dir / "existing_blocker.py").write_text(SHARED_HELPER_SOURCE, encoding="utf-8")
|
|
154
|
+
staging_directory = tmp_path_factory.mktemp("staging")
|
|
155
|
+
candidate_file = staging_directory / "candidate.py"
|
|
156
|
+
candidate_file.write_text(SHARED_HELPER_SOURCE, encoding="utf-8")
|
|
157
|
+
target_path = str(hook_blocking_dir / "new_blocker.py")
|
|
158
|
+
completed = subprocess.run(
|
|
159
|
+
[
|
|
160
|
+
sys.executable,
|
|
161
|
+
str(_ENFORCER_SCRIPT_PATH),
|
|
162
|
+
"--check",
|
|
163
|
+
str(candidate_file),
|
|
164
|
+
"--as",
|
|
165
|
+
target_path,
|
|
166
|
+
],
|
|
167
|
+
input="",
|
|
168
|
+
capture_output=True,
|
|
169
|
+
text=True,
|
|
170
|
+
check=False,
|
|
171
|
+
)
|
|
172
|
+
assert completed.returncode == 1, (
|
|
173
|
+
"a copied helper at a hook target must exit nonzero, got: "
|
|
174
|
+
f"{completed.returncode}, stdout: {completed.stdout!r}, "
|
|
175
|
+
f"stderr: {completed.stderr!r}"
|
|
176
|
+
)
|
|
177
|
+
assert "strip_code_and_quotes" in completed.stdout, (
|
|
178
|
+
f"the pre-check must name the duplicated helper, got: {completed.stdout!r}"
|
|
179
|
+
)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Tests for slice-bound magic values in the magic-value check.
|
|
2
|
+
|
|
3
|
+
CODE_RULES.md states only 0, 1, -1 (plus 0.0, 1.0) are exempt from the
|
|
4
|
+
magic-value check. A magic number used as a slice bound (``sha[:8]``,
|
|
5
|
+
``timestamp[:10]``) is still a magic value, while a plain subscript index
|
|
6
|
+
(``items[2]``) rides on the bracket exemption. The check distinguishes the
|
|
7
|
+
two by the colon a slice carries between its brackets.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import importlib.util
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from types import ModuleType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _load_enforcer_module() -> ModuleType:
|
|
18
|
+
module_path = Path(__file__).parent / "code_rules_enforcer.py"
|
|
19
|
+
spec = importlib.util.spec_from_file_location("code_rules_enforcer", module_path)
|
|
20
|
+
assert spec is not None
|
|
21
|
+
assert spec.loader is not None
|
|
22
|
+
module = importlib.util.module_from_spec(spec)
|
|
23
|
+
spec.loader.exec_module(module)
|
|
24
|
+
return module
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
code_rules_enforcer = _load_enforcer_module()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
PRODUCTION_FILE_PATH = "packages/claude-dev-env/skills/example/workflow/example_render.py"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_check_magic_values_should_flag_short_sha_slice_bound() -> None:
|
|
34
|
+
source = (
|
|
35
|
+
"def render_fix(fix_record):\n"
|
|
36
|
+
" short_sha = fix_record.new_sha[:8]\n"
|
|
37
|
+
" label = short_sha\n"
|
|
38
|
+
)
|
|
39
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
40
|
+
assert any(issue.endswith("Magic value 8 - extract to named constant") for issue in issues), (
|
|
41
|
+
f"Expected magic-value issue for slice bound 8, got: {issues}"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_check_magic_values_should_flag_iso_date_prefix_slice_bound() -> None:
|
|
46
|
+
source = (
|
|
47
|
+
"def read_date(journal):\n"
|
|
48
|
+
" timestamp = journal.get_timestamp()\n"
|
|
49
|
+
" generated = timestamp[:10]\n"
|
|
50
|
+
" label = generated\n"
|
|
51
|
+
)
|
|
52
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
53
|
+
assert any(issue.endswith("Magic value 10 - extract to named constant") for issue in issues), (
|
|
54
|
+
f"Expected magic-value issue for slice bound 10, got: {issues}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_check_magic_values_should_flag_slice_bound_even_with_inline_guard() -> None:
|
|
59
|
+
source = (
|
|
60
|
+
"def read_date(journal):\n"
|
|
61
|
+
" timestamp = journal.get_timestamp()\n"
|
|
62
|
+
' generated = timestamp[:10] if len(timestamp) >= 10 else ""\n'
|
|
63
|
+
" label = generated\n"
|
|
64
|
+
)
|
|
65
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
66
|
+
assert any(issue.endswith("Magic value 10 - extract to named constant") for issue in issues), (
|
|
67
|
+
f"Expected magic-value issue for slice bound 10 on a guarded line, got: {issues}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_check_magic_values_should_still_exempt_plain_subscript_index() -> None:
|
|
72
|
+
source = "def pick_entry(all_entries):\n chosen = all_entries[2]\n label = chosen\n"
|
|
73
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
74
|
+
assert issues == [], f"Expected no issues for a plain subscript index, got: {issues}"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_check_magic_values_should_allow_slice_bound_of_one() -> None:
|
|
78
|
+
source = "def first_character(text):\n head = text[:1]\n label = head\n"
|
|
79
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
80
|
+
assert issues == [], f"Expected no issues for an allowed slice bound 1, got: {issues}"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_check_magic_values_should_flag_slice_bound_not_substring_subscript_on_same_line() -> None:
|
|
84
|
+
source = (
|
|
85
|
+
"def join_pair(key, value):\n"
|
|
86
|
+
" pair = key[2] + value[:20]\n"
|
|
87
|
+
" label = pair\n"
|
|
88
|
+
)
|
|
89
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
90
|
+
assert any(issue.endswith("Magic value 20 - extract to named constant") for issue in issues), (
|
|
91
|
+
f"Expected the slice bound 20 to be flagged, got: {issues}"
|
|
92
|
+
)
|
|
93
|
+
assert not any(issue.endswith("Magic value 2 - extract to named constant") for issue in issues), (
|
|
94
|
+
f"Expected the subscript index 2 to stay exempt, got: {issues}"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_check_magic_values_should_flag_first_token_of_two_sided_slice() -> None:
|
|
99
|
+
source = "def middle(chunk):\n window = chunk[8:16]\n label = window\n"
|
|
100
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
101
|
+
assert any(issue.endswith("Magic value 8 - extract to named constant") for issue in issues), (
|
|
102
|
+
f"Expected the first slice bound 8 to be flagged, got: {issues}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_check_magic_values_should_exempt_walrus_subscript_index() -> None:
|
|
107
|
+
source = "def lookup(all_entries):\n chosen = all_entries[(n := 4)]\n label = chosen\n"
|
|
108
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
109
|
+
assert issues == [], f"Expected no issues for a walrus subscript index, got: {issues}"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_check_magic_values_should_exempt_lambda_subscript_index() -> None:
|
|
113
|
+
source = "def lookup(sequence):\n chosen = sequence[(lambda: 7)()]\n label = chosen\n"
|
|
114
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
115
|
+
assert issues == [], f"Expected no issues for a lambda subscript index, got: {issues}"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_check_magic_values_should_flag_outer_slice_bound_not_inner_subscript() -> None:
|
|
119
|
+
source = "def window(first, second):\n region = first[second[6]:9]\n label = region\n"
|
|
120
|
+
issues = code_rules_enforcer.check_magic_values(source, PRODUCTION_FILE_PATH)
|
|
121
|
+
assert any(issue.endswith("Magic value 9 - extract to named constant") for issue in issues), (
|
|
122
|
+
f"Expected the outer slice bound 9 to be flagged, got: {issues}"
|
|
123
|
+
)
|
|
124
|
+
assert not any(issue.endswith("Magic value 6 - extract to named constant") for issue in issues), (
|
|
125
|
+
f"Expected the inner subscript index 6 to stay exempt, got: {issues}"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_check_magic_values_should_pass_on_the_module_own_source() -> None:
|
|
130
|
+
module_path = Path(__file__).parent / "code_rules_magic_values.py"
|
|
131
|
+
source = module_path.read_text(encoding="utf-8")
|
|
132
|
+
issues = code_rules_enforcer.check_magic_values(source, str(module_path))
|
|
133
|
+
assert issues == [], f"Expected the module to pass its own magic-value check, got: {issues}"
|