claude-dev-env 1.62.1 → 1.64.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.
@@ -48,6 +48,7 @@ WRITE_CALL_REGION_PATTERN = (
48
48
  VERDICT_KEY_ALL_PASS = "all_pass"
49
49
  VERDICT_KEY_MANIFEST_SHA256 = "manifest_sha256"
50
50
  VERDICT_KEY_FINDINGS = "findings"
51
+ VERDICT_FILE_GLOB = "*.json"
51
52
  SUBAGENTS_DIRECTORY_NAME = "subagents"
52
53
  AGENT_TRANSCRIPT_GLOB = "agent-*.jsonl"
53
54
  AGENT_META_SIDECAR_SUFFIX = ".meta.json"
@@ -61,6 +62,21 @@ TRANSCRIPT_TEXT_CONTENT_TYPE = "text"
61
62
  TRANSCRIPT_TEXT_KEY = "text"
62
63
  VERDICT_FENCE_PATTERN = r"```verdict\s*\n(.*?)```"
63
64
  MANIFEST_HASH_CLI_FLAG = "--manifest-hash"
65
+ MANIFEST_HASH_FOR_BRANCH_CLI_FLAG = "--manifest-hash-for-branch"
66
+ WORKTREE_LIST_PATH_PREFIX = "worktree "
67
+ WORKTREE_LIST_BRANCH_PREFIX = "branch "
68
+ BRANCH_REFERENCE_PREFIX = "refs/heads/"
69
+ EMPTY_SURFACE_GUARD_MESSAGE = (
70
+ "ERROR: The work tree at {repo_root} has no changed or untracked files "
71
+ "versus origin/main (empty change surface). This work tree holds nothing "
72
+ "to verify — you are pointed at the wrong work tree. Run `git worktree list` "
73
+ "to see all checked-out work trees and target the one on the branch under review."
74
+ )
75
+ BRANCH_WORKTREE_ABSENT_MESSAGE = (
76
+ "ERROR: No work tree has branch '{branch}' checked out. "
77
+ "Check it out in a work tree first: "
78
+ "`git worktree add <path> <branch>` or `git checkout <branch>`."
79
+ )
64
80
  DOCS_ONLY_EXTENSIONS = frozenset(
65
81
  {".md", ".txt", ".rst", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico"}
66
82
  )
@@ -0,0 +1,534 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.util
4
+ from pathlib import Path
5
+
6
+ ENFORCER_PATH = Path(__file__).resolve().parent / "code_rules_enforcer.py"
7
+ specification = importlib.util.spec_from_file_location("code_rules_enforcer", ENFORCER_PATH)
8
+ assert specification is not None and specification.loader is not None
9
+ code_rules_enforcer = importlib.util.module_from_spec(specification)
10
+ specification.loader.exec_module(code_rules_enforcer)
11
+
12
+ PRODUCTION_FILE_PATH = "packages/app/services/render_report.py"
13
+ TEST_FILE_PATH = "packages/app/services/test_render_report.py"
14
+ MIGRATION_FILE_PATH = "packages/app/migrations/0001_initial.py"
15
+
16
+
17
+ def _check(source: str, file_path: str) -> list[str]:
18
+ return code_rules_enforcer.check_dead_argparse_arguments(source, file_path)
19
+
20
+
21
+ def test_should_flag_optional_argument_whose_dest_is_never_read() -> None:
22
+ source = (
23
+ "import argparse\n"
24
+ "\n"
25
+ "def build() -> None:\n"
26
+ " argument_parser = argparse.ArgumentParser()\n"
27
+ " argument_parser.add_argument('--repo', default='.')\n"
28
+ " parsed_arguments = argument_parser.parse_args()\n"
29
+ " print('done')\n"
30
+ )
31
+ issues = _check(source, PRODUCTION_FILE_PATH)
32
+ assert any("'repo'" in each_issue for each_issue in issues), (
33
+ f"Expected dead '--repo' argument flagged, got: {issues}"
34
+ )
35
+ assert any("Line 5" in each_issue for each_issue in issues), (
36
+ f"Expected the add_argument line reported, got: {issues}"
37
+ )
38
+
39
+
40
+ def test_should_not_flag_when_dest_is_read_via_attribute_access() -> None:
41
+ source = (
42
+ "import argparse\n"
43
+ "\n"
44
+ "def build() -> str:\n"
45
+ " argument_parser = argparse.ArgumentParser()\n"
46
+ " argument_parser.add_argument('--repo', default='.')\n"
47
+ " parsed_arguments = argument_parser.parse_args()\n"
48
+ " return parsed_arguments.repo\n"
49
+ )
50
+ assert _check(source, PRODUCTION_FILE_PATH) == []
51
+
52
+
53
+ def test_should_not_flag_a_positional_argument() -> None:
54
+ source = (
55
+ "import argparse\n"
56
+ "\n"
57
+ "def build() -> None:\n"
58
+ " argument_parser = argparse.ArgumentParser()\n"
59
+ " argument_parser.add_argument('path')\n"
60
+ " parsed_arguments = argument_parser.parse_args()\n"
61
+ " print('done')\n"
62
+ )
63
+ assert _check(source, PRODUCTION_FILE_PATH) == []
64
+
65
+
66
+ def test_should_not_flag_help_action_argument() -> None:
67
+ source = (
68
+ "import argparse\n"
69
+ "\n"
70
+ "def build() -> None:\n"
71
+ " argument_parser = argparse.ArgumentParser(add_help=False)\n"
72
+ " argument_parser.add_argument('--help', action='help')\n"
73
+ " parsed_arguments = argument_parser.parse_args()\n"
74
+ " print('done')\n"
75
+ )
76
+ assert _check(source, PRODUCTION_FILE_PATH) == []
77
+
78
+
79
+ def test_should_not_flag_version_action_argument() -> None:
80
+ source = (
81
+ "import argparse\n"
82
+ "\n"
83
+ "def build() -> None:\n"
84
+ " argument_parser = argparse.ArgumentParser()\n"
85
+ " argument_parser.add_argument('--version', action='version', version='1.0')\n"
86
+ " parsed_arguments = argument_parser.parse_args()\n"
87
+ " print('done')\n"
88
+ )
89
+ assert _check(source, PRODUCTION_FILE_PATH) == []
90
+
91
+
92
+ def test_should_respect_explicit_dest_when_unread() -> None:
93
+ source = (
94
+ "import argparse\n"
95
+ "\n"
96
+ "def build() -> None:\n"
97
+ " argument_parser = argparse.ArgumentParser()\n"
98
+ " argument_parser.add_argument('--repo', dest='repository')\n"
99
+ " parsed_arguments = argument_parser.parse_args()\n"
100
+ " print('done')\n"
101
+ )
102
+ issues = _check(source, PRODUCTION_FILE_PATH)
103
+ assert any("'repository'" in each_issue for each_issue in issues), (
104
+ f"Expected the explicit dest flagged, got: {issues}"
105
+ )
106
+ assert not any("'repo'" in each_issue for each_issue in issues), (
107
+ f"The option string must not be flagged when dest is explicit, got: {issues}"
108
+ )
109
+
110
+
111
+ def test_should_respect_explicit_dest_when_read() -> None:
112
+ source = (
113
+ "import argparse\n"
114
+ "\n"
115
+ "def build() -> str:\n"
116
+ " argument_parser = argparse.ArgumentParser()\n"
117
+ " argument_parser.add_argument('--repo', dest='repository')\n"
118
+ " parsed_arguments = argument_parser.parse_args()\n"
119
+ " return parsed_arguments.repository\n"
120
+ )
121
+ assert _check(source, PRODUCTION_FILE_PATH) == []
122
+
123
+
124
+ def test_should_skip_argument_with_non_literal_dest() -> None:
125
+ source = (
126
+ "import argparse\n"
127
+ "\n"
128
+ "DEST_NAME = 'repository'\n"
129
+ "\n"
130
+ "def build() -> str:\n"
131
+ " argument_parser = argparse.ArgumentParser()\n"
132
+ " argument_parser.add_argument('--repo', dest=DEST_NAME)\n"
133
+ " parsed_arguments = argument_parser.parse_args()\n"
134
+ " return parsed_arguments.repository\n"
135
+ )
136
+ assert _check(source, PRODUCTION_FILE_PATH) == []
137
+
138
+
139
+ def test_should_derive_dest_from_dashed_long_option() -> None:
140
+ source = (
141
+ "import argparse\n"
142
+ "\n"
143
+ "def build() -> bool:\n"
144
+ " argument_parser = argparse.ArgumentParser()\n"
145
+ " argument_parser.add_argument('--dry-run', action='store_true')\n"
146
+ " parsed_arguments = argument_parser.parse_args()\n"
147
+ " return parsed_arguments.dry_run\n"
148
+ )
149
+ assert _check(source, PRODUCTION_FILE_PATH) == []
150
+
151
+
152
+ def test_should_flag_dashed_long_option_when_dest_unread() -> None:
153
+ source = (
154
+ "import argparse\n"
155
+ "\n"
156
+ "def build() -> None:\n"
157
+ " argument_parser = argparse.ArgumentParser()\n"
158
+ " argument_parser.add_argument('--dry-run', action='store_true')\n"
159
+ " parsed_arguments = argument_parser.parse_args()\n"
160
+ " print('done')\n"
161
+ )
162
+ issues = _check(source, PRODUCTION_FILE_PATH)
163
+ assert any("'dry_run'" in each_issue for each_issue in issues), (
164
+ f"Expected the dashed long option dest flagged, got: {issues}"
165
+ )
166
+
167
+
168
+ def test_should_derive_dest_from_long_option_when_short_precedes() -> None:
169
+ source = (
170
+ "import argparse\n"
171
+ "\n"
172
+ "def build() -> None:\n"
173
+ " argument_parser = argparse.ArgumentParser()\n"
174
+ " argument_parser.add_argument('-r', '--repo')\n"
175
+ " parsed_arguments = argument_parser.parse_args()\n"
176
+ " print('done')\n"
177
+ )
178
+ issues = _check(source, PRODUCTION_FILE_PATH)
179
+ assert any("'repo'" in each_issue for each_issue in issues), (
180
+ f"Expected dest derived from the long option, got: {issues}"
181
+ )
182
+
183
+
184
+ def test_should_suppress_when_namespace_is_forwarded_to_a_call() -> None:
185
+ source = (
186
+ "import argparse\n"
187
+ "\n"
188
+ "def run(parsed_arguments: argparse.Namespace) -> None:\n"
189
+ " print('run')\n"
190
+ "\n"
191
+ "def build() -> None:\n"
192
+ " argument_parser = argparse.ArgumentParser()\n"
193
+ " argument_parser.add_argument('--repo', default='.')\n"
194
+ " parsed_arguments = argument_parser.parse_args()\n"
195
+ " run(parsed_arguments)\n"
196
+ )
197
+ assert _check(source, PRODUCTION_FILE_PATH) == []
198
+
199
+
200
+ def test_should_suppress_when_tuple_unpacked_namespace_is_forwarded() -> None:
201
+ source = (
202
+ "import argparse\n"
203
+ "\n"
204
+ "def main(parsed_arguments: argparse.Namespace) -> None:\n"
205
+ " print('run')\n"
206
+ "\n"
207
+ "def build() -> None:\n"
208
+ " argument_parser = argparse.ArgumentParser()\n"
209
+ " argument_parser.add_argument('--verbose', action='store_true')\n"
210
+ " parsed_arguments, remaining = argument_parser.parse_known_args()\n"
211
+ " main(parsed_arguments)\n"
212
+ )
213
+ assert _check(source, PRODUCTION_FILE_PATH) == []
214
+
215
+
216
+ def test_should_suppress_when_aliased_namespace_is_forwarded() -> None:
217
+ source = (
218
+ "import argparse\n"
219
+ "\n"
220
+ "def run(parsed_arguments: argparse.Namespace) -> None:\n"
221
+ " print('run')\n"
222
+ "\n"
223
+ "def build() -> None:\n"
224
+ " argument_parser = argparse.ArgumentParser()\n"
225
+ " argument_parser.add_argument('--repo', default='.')\n"
226
+ " parsed_arguments = argument_parser.parse_args()\n"
227
+ " alias = parsed_arguments\n"
228
+ " run(alias)\n"
229
+ )
230
+ assert _check(source, PRODUCTION_FILE_PATH) == []
231
+
232
+
233
+ def test_should_suppress_when_namespace_consumed_by_vars() -> None:
234
+ source = (
235
+ "import argparse\n"
236
+ "\n"
237
+ "def build() -> dict:\n"
238
+ " argument_parser = argparse.ArgumentParser()\n"
239
+ " argument_parser.add_argument('--repo', default='.')\n"
240
+ " parsed_arguments = argument_parser.parse_args()\n"
241
+ " return vars(parsed_arguments)\n"
242
+ )
243
+ assert _check(source, PRODUCTION_FILE_PATH) == []
244
+
245
+
246
+ def test_should_suppress_when_namespace_dict_accessed() -> None:
247
+ source = (
248
+ "import argparse\n"
249
+ "\n"
250
+ "def build() -> dict:\n"
251
+ " argument_parser = argparse.ArgumentParser()\n"
252
+ " argument_parser.add_argument('--repo', default='.')\n"
253
+ " parsed_arguments = argument_parser.parse_args()\n"
254
+ " return parsed_arguments.__dict__\n"
255
+ )
256
+ assert _check(source, PRODUCTION_FILE_PATH) == []
257
+
258
+
259
+ def test_should_be_silent_for_test_files() -> None:
260
+ source = (
261
+ "import argparse\n"
262
+ "\n"
263
+ "def build() -> None:\n"
264
+ " argument_parser = argparse.ArgumentParser()\n"
265
+ " argument_parser.add_argument('--repo', default='.')\n"
266
+ " parsed_arguments = argument_parser.parse_args()\n"
267
+ " print('done')\n"
268
+ )
269
+ assert _check(source, TEST_FILE_PATH) == []
270
+
271
+
272
+ def test_should_be_silent_for_migration_files() -> None:
273
+ source = (
274
+ "import argparse\n"
275
+ "\n"
276
+ "def build() -> None:\n"
277
+ " argument_parser = argparse.ArgumentParser()\n"
278
+ " argument_parser.add_argument('--repo', default='.')\n"
279
+ " parsed_arguments = argument_parser.parse_args()\n"
280
+ " print('done')\n"
281
+ )
282
+ assert _check(source, MIGRATION_FILE_PATH) == []
283
+
284
+
285
+ def test_should_tolerate_syntax_error() -> None:
286
+ assert _check("def broken(:\n", PRODUCTION_FILE_PATH) == []
287
+
288
+
289
+ def test_should_return_empty_when_no_add_argument_present() -> None:
290
+ source = "def build() -> int:\n return 1\n"
291
+ assert _check(source, PRODUCTION_FILE_PATH) == []
292
+
293
+
294
+ def test_should_suppress_when_namespace_unpacked_with_double_star() -> None:
295
+ source = (
296
+ "import argparse\n"
297
+ "\n"
298
+ "def run(repo: str) -> None:\n"
299
+ " print(repo)\n"
300
+ "\n"
301
+ "def build() -> None:\n"
302
+ " argument_parser = argparse.ArgumentParser()\n"
303
+ " argument_parser.add_argument('--repo', default='.')\n"
304
+ " parsed_arguments = argument_parser.parse_args()\n"
305
+ " run(**vars(parsed_arguments))\n"
306
+ )
307
+ assert _check(source, PRODUCTION_FILE_PATH) == []
308
+
309
+
310
+ def test_should_not_flag_when_dest_read_via_literal_getattr() -> None:
311
+ source = (
312
+ "import argparse\n"
313
+ "\n"
314
+ "def build() -> str:\n"
315
+ " argument_parser = argparse.ArgumentParser()\n"
316
+ " argument_parser.add_argument('--repo', default='.')\n"
317
+ " parsed_arguments = argument_parser.parse_args()\n"
318
+ " return getattr(parsed_arguments, 'repo')\n"
319
+ )
320
+ assert _check(source, PRODUCTION_FILE_PATH) == []
321
+
322
+
323
+ def test_should_suppress_when_namespace_stored_on_attribute_target() -> None:
324
+ source = (
325
+ "import argparse\n"
326
+ "\n"
327
+ "class App:\n"
328
+ " def build(self) -> None:\n"
329
+ " argument_parser = argparse.ArgumentParser()\n"
330
+ " argument_parser.add_argument('--repo', default='.')\n"
331
+ " argument_parser.add_argument('--verbose', action='store_true')\n"
332
+ " self.parsed_arguments = argument_parser.parse_args()\n"
333
+ "\n"
334
+ " def run(self) -> dict:\n"
335
+ " return dict(**vars(self.parsed_arguments))\n"
336
+ )
337
+ assert _check(source, PRODUCTION_FILE_PATH) == []
338
+
339
+
340
+ def test_should_suppress_when_parse_method_is_aliased() -> None:
341
+ source = (
342
+ "import argparse\n"
343
+ "\n"
344
+ "def run(parsed_arguments: argparse.Namespace) -> None:\n"
345
+ " print('run')\n"
346
+ "\n"
347
+ "def build() -> None:\n"
348
+ " argument_parser = argparse.ArgumentParser()\n"
349
+ " argument_parser.add_argument('--repo', default='.')\n"
350
+ " parse = argument_parser.parse_args\n"
351
+ " parsed_arguments = parse()\n"
352
+ " run(parsed_arguments)\n"
353
+ )
354
+ assert _check(source, PRODUCTION_FILE_PATH) == []
355
+
356
+
357
+ def test_should_suppress_when_namespace_forwarded_inside_container() -> None:
358
+ source = (
359
+ "import argparse\n"
360
+ "\n"
361
+ "def run(payload: dict) -> None:\n"
362
+ " print('run')\n"
363
+ "\n"
364
+ "def build() -> None:\n"
365
+ " argument_parser = argparse.ArgumentParser()\n"
366
+ " argument_parser.add_argument('--repo', default='.')\n"
367
+ " parsed_arguments = argument_parser.parse_args()\n"
368
+ " run({'args': parsed_arguments})\n"
369
+ )
370
+ assert _check(source, PRODUCTION_FILE_PATH) == []
371
+
372
+
373
+ def test_should_suppress_when_namespace_keyword_object_is_consumed() -> None:
374
+ source = (
375
+ "import argparse\n"
376
+ "\n"
377
+ "def build() -> dict:\n"
378
+ " options = argparse.Namespace()\n"
379
+ " argument_parser = argparse.ArgumentParser()\n"
380
+ " argument_parser.add_argument('--repo', default='.')\n"
381
+ " argument_parser.parse_args(namespace=options)\n"
382
+ " return vars(options)\n"
383
+ )
384
+ assert _check(source, PRODUCTION_FILE_PATH) == []
385
+
386
+
387
+ def test_should_suppress_when_namespace_keyword_object_is_forwarded() -> None:
388
+ source = (
389
+ "import argparse\n"
390
+ "\n"
391
+ "def run(parsed_arguments: argparse.Namespace) -> None:\n"
392
+ " print('run')\n"
393
+ "\n"
394
+ "def build() -> None:\n"
395
+ " options = argparse.Namespace()\n"
396
+ " argument_parser = argparse.ArgumentParser()\n"
397
+ " argument_parser.add_argument('--repo', default='.')\n"
398
+ " argument_parser.parse_args(namespace=options)\n"
399
+ " run(options)\n"
400
+ )
401
+ assert _check(source, PRODUCTION_FILE_PATH) == []
402
+
403
+
404
+ def test_should_flag_when_namespace_keyword_object_only_attribute_read() -> None:
405
+ source = (
406
+ "import argparse\n"
407
+ "\n"
408
+ "def build() -> str:\n"
409
+ " options = argparse.Namespace()\n"
410
+ " argument_parser = argparse.ArgumentParser()\n"
411
+ " argument_parser.add_argument('--repo', default='.')\n"
412
+ " argument_parser.add_argument('--verbose', action='store_true')\n"
413
+ " argument_parser.parse_args(namespace=options)\n"
414
+ " return options.repo\n"
415
+ )
416
+ issues = _check(source, PRODUCTION_FILE_PATH)
417
+ assert any("'verbose'" in each_issue for each_issue in issues), (
418
+ f"Expected the unread '--verbose' flag flagged, got: {issues}"
419
+ )
420
+ assert not any("'repo'" in each_issue for each_issue in issues), (
421
+ f"The read namespace= attribute must not be flagged, got: {issues}"
422
+ )
423
+
424
+
425
+ def test_should_suppress_when_parse_result_consumed_by_vars_inline() -> None:
426
+ source = (
427
+ "import argparse\n"
428
+ "\n"
429
+ "def build() -> dict:\n"
430
+ " argument_parser = argparse.ArgumentParser()\n"
431
+ " argument_parser.add_argument('--repo', default='.')\n"
432
+ " return vars(argument_parser.parse_args())\n"
433
+ )
434
+ assert _check(source, PRODUCTION_FILE_PATH) == []
435
+
436
+
437
+ def test_should_suppress_when_parse_result_returned_inline() -> None:
438
+ source = (
439
+ "import argparse\n"
440
+ "\n"
441
+ "def build() -> argparse.Namespace:\n"
442
+ " argument_parser = argparse.ArgumentParser()\n"
443
+ " argument_parser.add_argument('--repo', default='.')\n"
444
+ " return argument_parser.parse_args()\n"
445
+ )
446
+ assert _check(source, PRODUCTION_FILE_PATH) == []
447
+
448
+
449
+ def test_should_suppress_when_parse_result_double_star_unpacked_inline() -> None:
450
+ source = (
451
+ "import argparse\n"
452
+ "\n"
453
+ "def run(repo: str) -> None:\n"
454
+ " print(repo)\n"
455
+ "\n"
456
+ "def build() -> None:\n"
457
+ " argument_parser = argparse.ArgumentParser()\n"
458
+ " argument_parser.add_argument('--repo', default='.')\n"
459
+ " run(**vars(argument_parser.parse_args()))\n"
460
+ )
461
+ assert _check(source, PRODUCTION_FILE_PATH) == []
462
+
463
+
464
+ def test_should_flag_when_annotated_namespace_dest_is_unread() -> None:
465
+ source = (
466
+ "import argparse\n"
467
+ "\n"
468
+ "def build() -> None:\n"
469
+ " argument_parser = argparse.ArgumentParser()\n"
470
+ " argument_parser.add_argument('--repo', default='.')\n"
471
+ " parsed_arguments: argparse.Namespace = argument_parser.parse_args()\n"
472
+ " print('done')\n"
473
+ )
474
+ issues = _check(source, PRODUCTION_FILE_PATH)
475
+ assert any("'repo'" in each_issue for each_issue in issues), (
476
+ f"Expected the dead flag flagged through the annotated binding, got: {issues}"
477
+ )
478
+
479
+
480
+ def test_should_not_flag_when_annotated_namespace_dest_is_read() -> None:
481
+ source = (
482
+ "import argparse\n"
483
+ "\n"
484
+ "def build() -> str:\n"
485
+ " argument_parser = argparse.ArgumentParser()\n"
486
+ " argument_parser.add_argument('--repo', default='.')\n"
487
+ " parsed_arguments: argparse.Namespace = argument_parser.parse_args()\n"
488
+ " return parsed_arguments.repo\n"
489
+ )
490
+ assert _check(source, PRODUCTION_FILE_PATH) == []
491
+
492
+
493
+ def test_should_suppress_when_annotated_namespace_is_forwarded() -> None:
494
+ source = (
495
+ "import argparse\n"
496
+ "\n"
497
+ "def run(parsed_arguments: argparse.Namespace) -> None:\n"
498
+ " print('run')\n"
499
+ "\n"
500
+ "def build() -> None:\n"
501
+ " argument_parser = argparse.ArgumentParser()\n"
502
+ " argument_parser.add_argument('--repo', default='.')\n"
503
+ " parsed_arguments: argparse.Namespace = argument_parser.parse_args()\n"
504
+ " run(parsed_arguments)\n"
505
+ )
506
+ assert _check(source, PRODUCTION_FILE_PATH) == []
507
+
508
+
509
+ def test_should_suppress_when_parse_result_bound_by_walrus() -> None:
510
+ source = (
511
+ "import argparse\n"
512
+ "\n"
513
+ "def build() -> dict:\n"
514
+ " argument_parser = argparse.ArgumentParser()\n"
515
+ " argument_parser.add_argument('--repo', default='.')\n"
516
+ " return vars(parsed_arguments := argument_parser.parse_args())\n"
517
+ )
518
+ assert _check(source, PRODUCTION_FILE_PATH) == []
519
+
520
+
521
+ def test_validate_content_runs_dead_argparse_check() -> None:
522
+ source = (
523
+ "import argparse\n"
524
+ "\n"
525
+ "def build() -> None:\n"
526
+ " argument_parser = argparse.ArgumentParser()\n"
527
+ " argument_parser.add_argument('--repo', default='.')\n"
528
+ " parsed_arguments = argument_parser.parse_args()\n"
529
+ " print('done')\n"
530
+ )
531
+ issues = code_rules_enforcer.validate_content(source, PRODUCTION_FILE_PATH)
532
+ assert any("'repo'" in each_issue for each_issue in issues), (
533
+ f"Expected the enforcer dispatch to surface the dead argument, got: {issues}"
534
+ )