claude-dev-env 2.28.0 → 2.29.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 (212) hide show
  1. package/.agents/agents/AGENTS.md +0 -31
  2. package/.agents/agents/clean-coder.md +1 -1
  3. package/.agents/agents/test_agent_frontmatter.py +3 -1
  4. package/.agents/skills/AGENTS.md +0 -70
  5. package/.agents/skills/_shared/AGENTS.md +0 -44
  6. package/.agents/skills/_shared/advisor/AGENTS.md +0 -8
  7. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -57
  8. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -8
  9. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -34
  10. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -23
  11. package/.agents/skills/autoconverge/AGENTS.md +0 -35
  12. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -15
  13. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -25
  14. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -15
  15. package/.agents/skills/everything-search/AGENTS.md +0 -16
  16. package/.agents/skills/fresh-branch/AGENTS.md +0 -13
  17. package/.agents/skills/grok-spawn/AGENTS.md +0 -27
  18. package/.agents/skills/orchestrator/.claude/CLAUDE.md +1 -0
  19. package/.agents/skills/orchestrator/AGENTS.md +1 -0
  20. package/.agents/skills/orchestrator/SKILL.md +44 -53
  21. package/.agents/skills/orchestrator/reference/.claude/CLAUDE.md +1 -0
  22. package/.agents/skills/orchestrator/reference/AGENTS.md +1 -0
  23. package/.agents/skills/orchestrator/reference/consult-the-orchestrator.md +70 -0
  24. package/.agents/skills/orchestrator/reference/executor-consult-block.md +62 -0
  25. package/.agents/skills/orchestrator/reference/host-detect.md +15 -0
  26. package/.agents/skills/orchestrator/test_orchestrator_skill_contract.py +62 -0
  27. package/.agents/skills/orchestrator-refresh/SKILL.md +16 -34
  28. package/.agents/skills/rebase/AGENTS.md +0 -31
  29. package/.agents/skills/session-log/AGENTS.md +0 -31
  30. package/.agents/skills/session-tidy/AGENTS.md +0 -35
  31. package/.agents/skills/skill-builder/AGENTS.md +0 -48
  32. package/.agents/skills/skill-builder/references/AGENTS.md +0 -24
  33. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -13
  34. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -18
  35. package/.agents/skills/task-build/AGENTS.md +0 -28
  36. package/.agents/skills/update/AGENTS.md +0 -37
  37. package/.agents/skills-archived/AGENTS.md +0 -44
  38. package/.agents/skills-archived/anthropic-plan/AGENTS.md +0 -33
  39. package/.agents/skills-archived/anthropic-plan/scripts/AGENTS.md +0 -10
  40. package/.agents/skills-archived/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +0 -15
  41. package/.agents/skills-archived/anthropic-plan/templates/AGENTS.md +0 -12
  42. package/.agents/skills-archived/anthropic-plan/workflow/AGENTS.md +0 -13
  43. package/.agents/skills-archived/auditing-claude-config/AGENTS.md +0 -20
  44. package/.agents/skills-archived/bugteam/AGENTS.md +0 -29
  45. package/.agents/skills-archived/bugteam/reference/AGENTS.md +0 -19
  46. package/.agents/skills-archived/bugteam/reference/obstacles/AGENTS.md +0 -23
  47. package/.agents/skills-archived/bugteam/scripts/AGENTS.md +0 -29
  48. package/.agents/skills-archived/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +0 -17
  49. package/.agents/skills-archived/codex-review/AGENTS.md +0 -45
  50. package/.agents/skills-archived/codex-review/reference/AGENTS.md +0 -14
  51. package/.agents/skills-archived/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +0 -17
  52. package/.agents/skills-archived/codex-review/test_skill_scaffold.py +13 -3
  53. package/.agents/skills-archived/copilot-review/AGENTS.md +0 -17
  54. package/.agents/skills-archived/pr-converge/AGENTS.md +0 -31
  55. package/.agents/skills-archived/pr-converge/pr_converge_skill_constants/AGENTS.md +0 -25
  56. package/.agents/skills-archived/pr-converge/reference/AGENTS.md +0 -27
  57. package/.agents/skills-archived/pr-converge/reference/obstacles/AGENTS.md +0 -22
  58. package/.agents/skills-archived/pr-converge/scripts/AGENTS.md +0 -45
  59. package/.agents/skills-archived/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +0 -17
  60. package/.agents/skills-archived/pr-converge/workflows/AGENTS.md +0 -15
  61. package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
  62. package/.agents/skills-archived/recall/AGENTS.md +0 -29
  63. package/.agents/skills-archived/remember/AGENTS.md +0 -30
  64. package/AGENTS.md +0 -112
  65. package/_shared/AGENTS.md +0 -16
  66. package/_shared/advisor/AGENTS.md +0 -21
  67. package/_shared/advisor/advisor-protocol.md +4 -1
  68. package/_shared/advisor/reference/consult-format.md +4 -2
  69. package/_shared/pr-loop/AGENTS.md +0 -27
  70. package/_shared/pr-loop/scripts/AGENTS.md +0 -49
  71. package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +0 -41
  72. package/_shared/pr-loop/scripts/codex_review_scripts_constants/AGENTS.md +0 -17
  73. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/AGENTS.md +0 -17
  74. package/_shared/pr-loop/scripts/pr_converge_skill_constants/AGENTS.md +0 -25
  75. package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +0 -25
  76. package/_shared/pr-loop/scripts/tests/AGENTS.md +0 -43
  77. package/_shared/process-tree/AGENTS.md +0 -40
  78. package/audit-rubrics/AGENTS.md +0 -42
  79. package/audit-rubrics/category_rubrics/AGENTS.md +0 -36
  80. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +16 -29
  81. package/audit-rubrics/prompts/AGENTS.md +0 -36
  82. package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +2 -2
  83. package/bin/AGENTS.md +0 -118
  84. package/bin/install.test.mjs +1 -1
  85. package/commands/AGENTS.md +0 -14
  86. package/docs/AGENTS.md +0 -31
  87. package/docs/CODE_RULES.md +3 -3
  88. package/docs/agent-spawn-protocol.md +1 -1
  89. package/docs/references/AGENTS.md +0 -16
  90. package/docs/references/prose-style-enforcement.md +5 -9
  91. package/hooks/AGENTS.md +0 -27
  92. package/hooks/advisory/AGENTS.md +0 -15
  93. package/hooks/blocking/AGENTS.md +0 -122
  94. package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +0 -27
  95. package/hooks/blocking/code_rules_docstrings.py +10 -2138
  96. package/hooks/blocking/code_rules_enforcer.py +0 -121
  97. package/hooks/blocking/code_rules_imports_logging.py +1 -236
  98. package/hooks/blocking/code_rules_shared.py +23 -0
  99. package/hooks/blocking/code_rules_test_layout.py +8 -8
  100. package/hooks/blocking/config/AGENTS.md +0 -9
  101. package/hooks/blocking/config/prose_style_enforcement_constants.py +4 -2
  102. package/hooks/blocking/config/test_prose_style_enforcement_constants.py +5 -1
  103. package/hooks/blocking/inventory_intent_records/AGENTS.md +0 -25
  104. package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +0 -25
  105. package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +0 -23
  106. package/hooks/blocking/precommit_code_rules_gate.py +8 -43
  107. package/hooks/blocking/state_description_blocker.py +1 -7
  108. package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +0 -29
  109. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
  110. package/hooks/blocking/test_code_rules_enforcer_dispatch_wiring.py +0 -8
  111. package/hooks/blocking/test_code_rules_enforcer_module_docstring_roster.py +11 -112
  112. package/hooks/blocking/test_code_rules_enforcer_narrow_edit.py +0 -1
  113. package/hooks/blocking/test_code_rules_enforcer_split_entry_1.py +1 -18
  114. package/hooks/blocking/test_code_rules_shared.py +12 -0
  115. package/hooks/blocking/test_precommit_code_rules_gate.py +32 -179
  116. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -1
  117. package/hooks/blocking/test_state_description_blocker.py +6 -4
  118. package/hooks/blocking/test_stop_dispatcher.py +5 -29
  119. package/hooks/git-hooks/AGENTS.md +0 -31
  120. package/hooks/git-hooks/git_hooks_constants/AGENTS.md +0 -20
  121. package/hooks/hooks_constants/AGENTS.md +0 -104
  122. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -1
  123. package/hooks/hooks_constants/code_rules_enforcer_constants.py +3 -0
  124. package/hooks/hooks_constants/messages.py +0 -2
  125. package/hooks/hooks_constants/precommit_code_rules_gate_constants.py +3 -17
  126. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -2
  127. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -1
  128. package/hooks/hooks_constants/test_code_rules_enforcer_constants.py +7 -0
  129. package/hooks/hooks_constants/test_messages.py +5 -3
  130. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -2
  131. package/hooks/lifecycle/AGENTS.md +0 -17
  132. package/hooks/observability/AGENTS.md +0 -19
  133. package/hooks/session/AGENTS.md +0 -37
  134. package/hooks/validation/AGENTS.md +0 -19
  135. package/hooks/validators/AGENTS.md +0 -51
  136. package/hooks/workflow/AGENTS.md +0 -15
  137. package/output-styles/AGENTS.md +0 -14
  138. package/package.json +1 -1
  139. package/rules/AGENTS.md +0 -58
  140. package/rules/claims-as-quotes.md +0 -10
  141. package/rules/code-standards.md +6 -6
  142. package/rules/explore-thoroughly.md +0 -1
  143. package/rules/failure-blast-radius.md +0 -8
  144. package/rules/falsify-before-green.md +0 -8
  145. package/rules/file-global-constants.md +2 -2
  146. package/rules/filesystem-search.md +1 -1
  147. package/rules/git-workflow.md +1 -9
  148. package/rules/hedging-claims.md +2 -6
  149. package/rules/long-horizon-autonomy.md +1 -1
  150. package/rules/measurement-denominators.md +0 -9
  151. package/rules/research-mode.md +0 -6
  152. package/rules/verify-before-asking.md +0 -5
  153. package/rules/verify-runtime-state.md +0 -5
  154. package/scripts/AGENTS.md +0 -55
  155. package/scripts/codex_compat_materializer.py +0 -12
  156. package/scripts/dev_env_scripts_constants/AGENTS.md +0 -20
  157. package/scripts/sync_to_cursor/AGENTS.md +0 -22
  158. package/scripts/sync_to_cursor/rules.py +0 -10
  159. package/scripts/tests/AGENTS.md +0 -34
  160. package/scripts/tests/test_engine.py +0 -1
  161. package/scripts/tests/test_rules.py +0 -1
  162. package/scripts/tests/test_sync_to_cursor.py +0 -1
  163. package/system-prompts/AGENTS.md +0 -24
  164. package/system-prompts/software-engineer.xml +3 -3
  165. package/hooks/blocking/code_rules_dead_argparse_argument.py +0 -554
  166. package/hooks/blocking/code_rules_dead_config_field.py +0 -568
  167. package/hooks/blocking/code_rules_dead_dataclass_field.py +0 -348
  168. package/hooks/blocking/code_rules_dead_module_constant.py +0 -757
  169. package/hooks/blocking/code_rules_dead_split_branch.py +0 -225
  170. package/hooks/blocking/code_rules_mock_completeness.py +0 -295
  171. package/hooks/blocking/code_rules_scope_binding.py +0 -151
  172. package/hooks/blocking/code_rules_unused_imports.py +0 -197
  173. package/hooks/blocking/hedging_language_blocker.py +0 -221
  174. package/hooks/blocking/intent_only_ending_blocker.py +0 -148
  175. package/hooks/blocking/test_code_rules_enforcer_dead_argparse_argument.py +0 -534
  176. package/hooks/blocking/test_code_rules_enforcer_dead_config_field.py +0 -846
  177. package/hooks/blocking/test_code_rules_enforcer_dead_dataclass_field.py +0 -507
  178. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +0 -679
  179. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant_alias.py +0 -133
  180. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant_read_cap.py +0 -103
  181. package/hooks/blocking/test_code_rules_enforcer_dead_split_branch.py +0 -105
  182. package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +0 -425
  183. package/hooks/blocking/test_code_rules_enforcer_docstring_cardinal_family.py +0 -176
  184. package/hooks/blocking/test_code_rules_enforcer_docstring_delegation_summary.py +0 -385
  185. package/hooks/blocking/test_code_rules_enforcer_docstring_fallback_branch.py +0 -398
  186. package/hooks/blocking/test_code_rules_enforcer_docstring_field_runmode_outcome.py +0 -129
  187. package/hooks/blocking/test_code_rules_enforcer_docstring_inline_literal_claim.py +0 -93
  188. package/hooks/blocking/test_code_rules_enforcer_docstring_length_constant_superlative.py +0 -198
  189. package/hooks/blocking/test_code_rules_enforcer_docstring_mark_glyph_enumeration.py +0 -262
  190. package/hooks/blocking/test_code_rules_enforcer_docstring_no_consumer.py +0 -93
  191. package/hooks/blocking/test_code_rules_enforcer_docstring_no_network.py +0 -115
  192. package/hooks/blocking/test_code_rules_enforcer_docstring_raises_largezipfile.py +0 -226
  193. package/hooks/blocking/test_code_rules_enforcer_docstring_returns_plural_cardinality.py +0 -207
  194. package/hooks/blocking/test_code_rules_enforcer_docstring_step_dispatch.py +0 -262
  195. package/hooks/blocking/test_code_rules_enforcer_docstring_type_checking_gate.py +0 -164
  196. package/hooks/blocking/test_code_rules_enforcer_docstring_unguarded_payload.py +0 -188
  197. package/hooks/blocking/test_code_rules_enforcer_import_block_sort.py +0 -157
  198. package/hooks/blocking/test_code_rules_enforcer_split_mocks_1.py +0 -303
  199. package/hooks/blocking/test_code_rules_enforcer_split_mocks_2.py +0 -111
  200. package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +0 -656
  201. package/hooks/blocking/test_hedging_language_blocker.py +0 -261
  202. package/hooks/blocking/test_intent_only_ending_blocker.py +0 -209
  203. package/hooks/hooks_constants/dead_argparse_argument_constants.py +0 -28
  204. package/hooks/hooks_constants/dead_config_field_constants.py +0 -39
  205. package/hooks/hooks_constants/dead_dataclass_field_constants.py +0 -25
  206. package/hooks/hooks_constants/dead_module_constant_constants.py +0 -30
  207. package/hooks/hooks_constants/hedging_uncertainty_constants.py +0 -42
  208. package/hooks/hooks_constants/test_dispatcher_constants_docstrings.py +0 -44
  209. package/rules/conservative-action.md +0 -17
  210. package/rules/context7.md +0 -8
  211. package/rules/few-words.md +0 -3
  212. package/rules/parallel-tools.md +0 -23
@@ -1,133 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import importlib.util
4
- import os
5
- import shutil
6
- import stat
7
- import tempfile
8
- from collections.abc import Callable, Iterator
9
- from pathlib import Path
10
-
11
- import pytest
12
-
13
- ENFORCER_PATH = Path(__file__).resolve().parent / "code_rules_enforcer.py"
14
- specification = importlib.util.spec_from_file_location("code_rules_enforcer", ENFORCER_PATH)
15
- assert specification is not None and specification.loader is not None
16
- code_rules_enforcer = importlib.util.module_from_spec(specification)
17
- specification.loader.exec_module(code_rules_enforcer)
18
-
19
- CONSTANTS_BODY = 'MEDIUM_TERMINAL = "terminal"\nMEDIUM_CODE = "code"\nMEDIUM_TEXT = "text"\n'
20
-
21
-
22
- def _strip_read_only_and_retry(
23
- removal_function: Callable[[str], object],
24
- target_path: str,
25
- _exc_info: BaseException,
26
- ) -> None:
27
- try:
28
- os.chmod(target_path, stat.S_IWRITE)
29
- removal_function(target_path)
30
- except OSError:
31
- pass
32
-
33
-
34
- @pytest.fixture
35
- def neutral_root() -> Iterator[Path]:
36
- """Yield a temp directory whose path carries no ``test_`` segment.
37
-
38
- ::
39
-
40
- tmp_path (pytest default) -> embeds "test_..." in its name
41
- -> is_test_file() misreads the path
42
- mkdtemp(prefix="deadconst-") -> no "test_" segment -> reads as
43
- a production path ok
44
-
45
- A ``.git`` marker is planted at the root so the cross-tree widening
46
- resolves the repository root to this synthetic tree.
47
- """
48
- neutral_directory = Path(tempfile.mkdtemp(prefix="deadconst-")).resolve()
49
- (neutral_directory / ".git").mkdir()
50
- try:
51
- yield neutral_directory
52
- finally:
53
- shutil.rmtree(neutral_directory, onexc=_strip_read_only_and_retry)
54
-
55
-
56
- def _check(source: str, file_path: str) -> list[str]:
57
- return code_rules_enforcer.check_dead_module_constants(source, file_path)
58
-
59
-
60
- def _build_constants_package(
61
- workflow_directory: Path,
62
- constants_body: str,
63
- consumer_body: str,
64
- ) -> Path:
65
- constants_package = workflow_directory / "report_constants"
66
- constants_package.mkdir(parents=True)
67
- (constants_package / "__init__.py").write_text("", encoding="utf-8")
68
- constants_path = constants_package / "render_report_constants.py"
69
- constants_path.write_text(constants_body, encoding="utf-8")
70
- (workflow_directory / "render_report.py").write_text(consumer_body, encoding="utf-8")
71
- return constants_path
72
-
73
-
74
- def _assert_alias_read_constants_live(issues: list[str]) -> None:
75
- assert not any(
76
- "MEDIUM_TERMINAL" in each_issue or "MEDIUM_CODE" in each_issue for each_issue in issues
77
- ), f"A constant read as attribute of an imported module stays live, got: {issues}"
78
- assert any("MEDIUM_TEXT" in each_issue for each_issue in issues), (
79
- f"A constant read by no module must still be flagged, got: {issues}"
80
- )
81
-
82
-
83
- def test_does_not_flag_constant_read_via_from_import_module_alias_attribute(
84
- neutral_root: Path,
85
- ) -> None:
86
- consumer_body = (
87
- "from report_constants import render_report_constants as constants\n"
88
- "\n"
89
- "def panel_class(medium: str) -> str:\n"
90
- " if medium == constants.MEDIUM_TERMINAL:\n"
91
- " return 'terminal'\n"
92
- " return 'code' if medium == constants.MEDIUM_CODE else 'other'\n"
93
- )
94
- constants_path = _build_constants_package(
95
- neutral_root / "workflow", CONSTANTS_BODY, consumer_body
96
- )
97
- _assert_alias_read_constants_live(_check(CONSTANTS_BODY, str(constants_path)))
98
-
99
-
100
- def test_does_not_flag_constant_read_via_import_as_alias_attribute(
101
- neutral_root: Path,
102
- ) -> None:
103
- consumer_body = (
104
- "import report_constants.render_report_constants as constants\n"
105
- "\n"
106
- "def label(medium: str) -> str:\n"
107
- " if medium == constants.MEDIUM_TERMINAL:\n"
108
- " return 'terminal'\n"
109
- " return 'code' if medium == constants.MEDIUM_CODE else 'other'\n"
110
- )
111
- constants_path = _build_constants_package(
112
- neutral_root / "workflow", CONSTANTS_BODY, consumer_body
113
- )
114
- _assert_alias_read_constants_live(_check(CONSTANTS_BODY, str(constants_path)))
115
-
116
-
117
- def test_does_not_flag_constant_read_via_plain_module_name_attribute(
118
- neutral_root: Path,
119
- ) -> None:
120
- consumer_body = (
121
- "from report_constants import render_report_constants\n"
122
- "\n"
123
- "def label(medium: str) -> str:\n"
124
- " if medium == render_report_constants.MEDIUM_TERMINAL:\n"
125
- " return 'terminal'\n"
126
- " if medium == render_report_constants.MEDIUM_CODE:\n"
127
- " return 'code'\n"
128
- " return 'other'\n"
129
- )
130
- constants_path = _build_constants_package(
131
- neutral_root / "workflow", CONSTANTS_BODY, consumer_body
132
- )
133
- _assert_alias_read_constants_live(_check(CONSTANTS_BODY, str(constants_path)))
@@ -1,103 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import importlib.util
4
- import os
5
- import shutil
6
- import stat
7
- import tempfile
8
- from collections.abc import Callable, Iterator
9
- from pathlib import Path
10
-
11
- import pytest
12
-
13
- ENFORCER_PATH = Path(__file__).resolve().parent / "code_rules_enforcer.py"
14
- specification = importlib.util.spec_from_file_location("code_rules_enforcer", ENFORCER_PATH)
15
- assert specification is not None and specification.loader is not None
16
- code_rules_enforcer = importlib.util.module_from_spec(specification)
17
- specification.loader.exec_module(code_rules_enforcer)
18
-
19
-
20
- def _strip_read_only_and_retry(
21
- removal_function: Callable[[str], object],
22
- target_path: str,
23
- _exc_info: BaseException,
24
- ) -> None:
25
- try:
26
- os.chmod(target_path, stat.S_IWRITE)
27
- removal_function(target_path)
28
- except OSError:
29
- pass
30
-
31
-
32
- @pytest.fixture
33
- def neutral_root() -> Iterator[Path]:
34
- """Yield a temp directory whose path carries no ``test_`` segment.
35
-
36
- ::
37
-
38
- tmp_path (pytest default) -> embeds "test_..." in its name
39
- -> is_test_file() misreads every
40
- synthetic constants path
41
- mkdtemp(prefix="deadconst-") -> no "test_" segment
42
- -> reads as a production path ok
43
-
44
- A ``.git`` marker is planted at the root so the cross-tree widening
45
- resolves the repository root to this synthetic tree.
46
- """
47
- neutral_directory = Path(tempfile.mkdtemp(prefix="deadconst-")).resolve()
48
- (neutral_directory / ".git").mkdir()
49
- try:
50
- yield neutral_directory
51
- finally:
52
- shutil.rmtree(neutral_directory, onexc=_strip_read_only_and_retry)
53
-
54
-
55
- def _check(source: str, file_path: str) -> list[str]:
56
- return code_rules_enforcer.check_dead_module_constants(source, file_path)
57
-
58
-
59
- def _write_noise_modules(directory: Path, count: int) -> None:
60
- directory.mkdir(parents=True)
61
- for each_index in range(count):
62
- (directory / f"mod_{each_index}.py").write_text(
63
- "def noop() -> int:\n return 1\n", encoding="utf-8"
64
- )
65
-
66
-
67
- def test_widened_scan_bounds_total_disk_reads_on_noncandidate_flood(
68
- neutral_root: Path, monkeypatch: pytest.MonkeyPatch
69
- ) -> None:
70
- """A read-attempt cap stops the widened pass from reading every sibling.
71
-
72
- ::
73
-
74
- MAX_SCAN_ROOT_READ_COUNT = 3, 50 non-candidate noise files
75
- ok: read_text() called a bounded number of times (< 50)
76
- flag: read_text() called once per noise file (== 50)
77
-
78
- Without the cap, ``_read_candidate_source`` opens and reads every
79
- repository ``.py`` file's full text before testing it for the module
80
- stem, so disk-read cost scales with repository size regardless of how
81
- quickly the file cap would otherwise stop the parse-and-collect work.
82
- """
83
- monkeypatch.setattr("code_rules_dead_module_constant.MAX_SCAN_ROOT_READ_COUNT", 3)
84
- package_directory = neutral_root / "pkg"
85
- package_directory.mkdir(parents=True)
86
- constants_body = 'DEAD_EXPORTED = "x"\n__all__ = ["DEAD_EXPORTED"]\n'
87
- constants_path = package_directory / "settings_constants.py"
88
- constants_path.write_text(constants_body, encoding="utf-8")
89
- _write_noise_modules(neutral_root / "noise", 50)
90
- read_count = 0
91
- original_read_text = Path.read_text
92
-
93
- def counting_read_text(self: Path, *positional: object, **keyword: object) -> str:
94
- nonlocal read_count
95
- read_count += 1
96
- return original_read_text(self, *positional, **keyword) # type: ignore[arg-type] # forwards positional/keyword args mypy cannot resolve
97
-
98
- monkeypatch.setattr(Path, "read_text", counting_read_text)
99
- _check(constants_body, str(constants_path))
100
- assert read_count < 50, (
101
- "A read-count cap must stop the widened pass from reading every "
102
- f"non-candidate sibling's full text, got {read_count} reads across 50 noise files"
103
- )
@@ -1,105 +0,0 @@
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_PATH = "C:/project/pkg/menu_info_colors.py"
13
-
14
-
15
- def _check(source: str) -> list[str]:
16
- return code_rules_enforcer.check_dead_split_truthiness_branch(source, PRODUCTION_PATH)
17
-
18
-
19
- def test_flags_split_truthiness_else_arm() -> None:
20
- source = (
21
- "def _extract_uid_prefix(uid: str) -> str:\n"
22
- ' all_parts = uid.split("_")\n'
23
- " if len(all_parts) > 2:\n"
24
- ' return "_".join(all_parts[:3])\n'
25
- " return all_parts[0] if all_parts else uid\n"
26
- )
27
- issues = _check(source)
28
- assert len(issues) == 1
29
- assert "all_parts" in issues[0]
30
- assert "Line 5" in issues[0]
31
-
32
-
33
- def test_flags_negated_guard_dead_body() -> None:
34
- source = (
35
- "def first_segment(path: str) -> str:\n"
36
- ' all_segments = path.split("/")\n'
37
- " if not all_segments:\n"
38
- " return path\n"
39
- " return all_segments[0]\n"
40
- )
41
- issues = _check(source)
42
- assert len(issues) == 1
43
- assert "all_segments" in issues[0]
44
-
45
-
46
- def test_does_not_flag_split_without_separator() -> None:
47
- source = (
48
- "def first_token(text: str) -> str:\n"
49
- " all_parts = text.split()\n"
50
- " return all_parts[0] if all_parts else text\n"
51
- )
52
- assert _check(source) == []
53
-
54
-
55
- def test_does_not_flag_length_comparison_guard() -> None:
56
- source = (
57
- "def prefix(uid: str) -> str:\n"
58
- ' all_parts = uid.split("_")\n'
59
- " if len(all_parts) > 1:\n"
60
- " return all_parts[0]\n"
61
- " return uid\n"
62
- )
63
- assert _check(source) == []
64
-
65
-
66
- def test_does_not_flag_when_name_reassigned() -> None:
67
- source = (
68
- "def normalize(uid: str) -> str:\n"
69
- ' all_parts = uid.split("_")\n'
70
- " all_parts = [each_part.strip() for each_part in all_parts]\n"
71
- " return all_parts[0] if all_parts else uid\n"
72
- )
73
- assert _check(source) == []
74
-
75
-
76
- def test_does_not_flag_when_name_is_parameter() -> None:
77
- source = (
78
- "def shape(all_parts: list[str]) -> str:\n"
79
- ' all_parts = "x".split("_")\n'
80
- ' return all_parts[0] if all_parts else ""\n'
81
- )
82
- assert _check(source) == []
83
-
84
-
85
- def test_does_not_flag_attribute_receiver_split() -> None:
86
- source = (
87
- "def first(s: object) -> object:\n"
88
- ' parts = s.str.split(",")\n'
89
- " return parts[0] if parts else 0\n"
90
- )
91
- assert _check(source) == []
92
-
93
-
94
- def test_does_not_flag_in_test_file() -> None:
95
- source = (
96
- "def helper(uid: str) -> str:\n"
97
- ' all_parts = uid.split("_")\n'
98
- " return all_parts[0] if all_parts else uid\n"
99
- )
100
- assert (
101
- code_rules_enforcer.check_dead_split_truthiness_branch(
102
- source, "C:/project/pkg/test_thing.py"
103
- )
104
- == []
105
- )