claude-dev-env 8.46.3 → 8.46.5

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.
@@ -135,7 +135,7 @@ Consult the advisor the spawn ticket names. When the ticket names the orchestrat
135
135
  [3] Parameters and returns typed; no Any / no type-ignore directives?
136
136
  [4] Do not add code comments. Preserve existing comments. Docstrings remain allowed.
137
137
  [5] When a change touches code that an existing comment describes or is attached to, remove that comment in the same change and carry its meaning through clear names and structure. Leave comments tied to untouched code unchanged. Keep comment cleanup inside the requested task.
138
- [6] Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed rather than added or justified.
138
+ [6] Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed. Do not add or justify them.
139
139
  [7] Magic values and UPPER_SNAKE live in config/ where required?
140
140
  [8] Function short; one job; guards over else-chains?
141
141
  [9] Pre-check --check clean for the real destination path?
@@ -63,7 +63,7 @@ Tradeoff for category-restricted mode: parallel category invocation loses cross-
63
63
 
64
64
  Leave comments tied to untouched code unchanged. Findings on production and test code report only on new code added by the diff; comments on lines that remain otherwise unchanged stay outside the audit's scope. New inline comments added by this PR's diff are themselves a category J finding (code self-documents through naming).
65
65
  When a change touches code that an existing comment describes or is attached to, remove that comment in the same change and carry its meaning through clear names and structure. Leave comments tied to untouched code unchanged. Keep comment cleanup inside the requested task.
66
- Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed rather than added or justified.
66
+ Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed. Do not add or justify them.
67
67
 
68
68
  ## Read-Only Stance
69
69
 
@@ -63,7 +63,7 @@ You edit code and run tests for one closed task. You never commit, push, or call
63
63
 
64
64
  Do not add code comments. Preserve existing comments. Docstrings remain allowed.
65
65
  When a change touches code that an existing comment describes or is attached to, remove that comment in the same change and carry its meaning through clear names and structure. Leave comments tied to untouched code unchanged. Keep comment cleanup inside the requested task.
66
- Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed rather than added or justified.
66
+ Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed. Do not add or justify them.
67
67
 
68
68
  ## Scope
69
69
 
package/AGENTS.md CHANGED
@@ -68,7 +68,7 @@ Match requested status, paths, links, and format. Name files, checks, blockers,
68
68
 
69
69
  Do not add code comments. Preserve existing comments. Docstrings remain allowed.
70
70
  When a change touches code that an existing comment describes or is attached to, remove that comment in the same change and carry its meaning through clear names and structure. Leave comments tied to untouched code unchanged. Keep comment cleanup inside the requested task.
71
- Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed rather than added or justified.
71
+ Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed. Do not add or justify them.
72
72
 
73
73
  Banned word: real
74
74
 
@@ -7,7 +7,7 @@ Use this index for edits. [`.cursor/BUGBOT.md`](../../../.cursor/BUGBOT.md) poin
7
7
  Do not add code comments. Preserve existing comments. Docstrings remain allowed.
8
8
 
9
9
  When a change touches code that an existing comment describes or is attached to, remove that comment in the same change and carry its meaning through clear names and structure. Leave comments tied to untouched code unchanged. Keep comment cleanup inside the requested task.
10
- Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed rather than added or justified.
10
+ Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed. Do not add or justify them.
11
11
 
12
12
  A keep marker is the one comment that may be added and kept: a comment that opens with a prefix the repository lists under `comment_keep_markers` in `.claude/policy-lint.json`. Open [details](code-rules/comment-preservation.md) when editing comments.
13
13
 
@@ -201,10 +201,10 @@ def _is_keep_occurrence(comment_text: str, all_keep_markers: tuple[str, ...]) ->
201
201
  """Return True for a comment that opens with an accepted keep marker.
202
202
 
203
203
  A keep marker is meant to be freely added and to survive edits to the
204
- line it sits on, unlike ``noqa`` or ``TODO``, which AGENTS.md requires to
205
- be removed rather than added or justified. It is excluded here rather
206
- than through the shared exempt-marker set that ``check_comment_changes``
207
- deliberately still blocks on add.
204
+ line it sits on. AGENTS.md requires ``noqa`` and ``TODO`` comments to be
205
+ removed and forbids adding or justifying them. This check excludes keep
206
+ markers itself, outside the shared exempt-marker set that
207
+ ``check_comment_changes`` deliberately still blocks on add.
208
208
  """
209
209
  return comment_text.startswith("#") and comment_text[1:].lstrip().startswith(
210
210
  all_keep_markers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "8.46.3",
3
+ "version": "8.46.5",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,7 +11,7 @@ paths:
11
11
 
12
12
  # Flag non-breaking findings
13
13
 
14
- **When:** When writing a local gate or changing a check's severity.
14
+ **When:** Writing a local gate or changing a check's severity.
15
15
 
16
16
  Give every check ID a breaking or smell severity row; style and structure findings are smells. Fail the gate and stop for a bug, secret, broken test, syntax error, or instruction file that cannot load. Record a smell in `.claude/followups/smells.jsonl`, proceed, and fix it in a later pull request; ledger failure leaves the gate decision unchanged. Treat an unclassified check as breaking.
17
17
 
@@ -5,7 +5,7 @@ paths:
5
5
 
6
6
  # Rules prose names only hooks that run
7
7
 
8
- **When:** When describing a hook or retiring a gate.
8
+ **When:** Describing a hook or retiring a gate.
9
9
 
10
10
  Verify the module and its hook registration or dispatcher roster before claiming it runs; describe a retired hook in past tense or name the check that carries its work now. When retiring a gate, remove the forced agent calls, tokens, extra steps, thresholds, audit rubrics, and review prompts it required across every instruction lane. Add a retired hook path to the installer roster when deleting its module.
11
11
 
@@ -18,11 +18,15 @@ from codex_compat_materializer import (
18
18
  )
19
19
 
20
20
  FRONTMATTER_DELIMITER = "---"
21
+ FENCE_MARKER = "```"
21
22
  FULL_TEXT_LINK_PATTERN = re.compile(
22
23
  r"^\*\*Full text:\*\*.*?\]\((\.\./docs/rule-guides/[^)#\s]+\.md)\)", re.MULTILINE
23
24
  )
24
25
  TITLE_PATTERN = re.compile(r"^# \S", re.MULTILINE)
25
26
  WHEN_LINE_PATTERN = re.compile(r"^\*\*When(?: this applies)?:\*\* \S", re.MULTILINE)
27
+ DOUBLED_WHEN_LEAD_IN_PATTERN = re.compile(
28
+ r"^\*\*When(?: this applies)?:\*\* When\b", re.MULTILINE
29
+ )
26
30
 
27
31
  MAXIMUM_ENTRY_BYTES = 1_500
28
32
  MAXIMUM_ALWAYS_ON_BYTES = 12_000
@@ -90,16 +94,74 @@ def test_each_entry_opens_with_a_title_after_its_frontmatter() -> None:
90
94
  assert untitled == []
91
95
 
92
96
 
97
+ def _entry_body_before_full_text(entry_text: str) -> str:
98
+ _, entry_body = _split_frontmatter(entry_text)
99
+ all_kept_lines: list[str] = []
100
+ is_inside_fence = False
101
+ for each_line in entry_body.splitlines():
102
+ if FULL_TEXT_LINK_PATTERN.match(each_line):
103
+ break
104
+ if each_line.lstrip().startswith(FENCE_MARKER):
105
+ is_inside_fence = not is_inside_fence
106
+ continue
107
+ if not is_inside_fence:
108
+ all_kept_lines.append(each_line)
109
+ return "\n".join(all_kept_lines)
110
+
111
+
112
+ def _states_when_it_applies(entry_text: str) -> bool:
113
+ return bool(WHEN_LINE_PATTERN.search(_entry_body_before_full_text(entry_text)))
114
+
115
+
93
116
  def test_each_entry_states_when_it_applies() -> None:
94
117
  without_when_line = [
95
118
  each_path.name
96
119
  for each_path in _entry_paths()
97
120
  if each_path.name not in INDEX_SHAPE_EXEMPT_ENTRY_NAMES
98
- and not WHEN_LINE_PATTERN.search(_entry_text(each_path))
121
+ and not _states_when_it_applies(_entry_text(each_path))
99
122
  ]
100
123
  assert without_when_line == []
101
124
 
102
125
 
126
+ def test_when_line_inside_a_fenced_block_does_not_count() -> None:
127
+ entry_text = (
128
+ "# Example rule\n\n"
129
+ "```markdown\n**When:** Writing an example.\n```\n\n"
130
+ "**Full text:** [`docs/rule-guides/example.md`]"
131
+ "(../docs/rule-guides/example.md).\n"
132
+ )
133
+ assert not _states_when_it_applies(entry_text)
134
+
135
+
136
+ def test_when_line_below_the_full_text_link_does_not_count() -> None:
137
+ entry_text = (
138
+ "# Example rule\n\n"
139
+ "**Full text:** [`docs/rule-guides/example.md`]"
140
+ "(../docs/rule-guides/example.md).\n\n"
141
+ "**When:** Writing an example.\n"
142
+ )
143
+ assert not _states_when_it_applies(entry_text)
144
+
145
+
146
+ def test_when_line_in_the_entry_body_counts() -> None:
147
+ entry_text = (
148
+ "---\npaths:\n - \"**/*.py\"\n---\n\n# Example rule\n\n"
149
+ "**When:** Writing an example.\n\n"
150
+ "**Full text:** [`docs/rule-guides/example.md`]"
151
+ "(../docs/rule-guides/example.md).\n"
152
+ )
153
+ assert _states_when_it_applies(entry_text)
154
+
155
+
156
+ def test_no_entry_repeats_when_after_its_when_label() -> None:
157
+ doubled_lead_in = [
158
+ each_path.name
159
+ for each_path in _entry_paths()
160
+ if DOUBLED_WHEN_LEAD_IN_PATTERN.search(_entry_text(each_path))
161
+ ]
162
+ assert doubled_lead_in == []
163
+
164
+
103
165
  def _full_text_link_problems(entry_path: Path) -> list[str]:
104
166
  all_guide_names = _linked_guide_names(_entry_text(entry_path))
105
167
  if not all_guide_names:
@@ -116,7 +116,7 @@
116
116
  - Preserve existing comments.
117
117
  - Do not add code comments.
118
118
  - When a change touches code that an existing comment describes or is attached to, remove that comment in the same change and carry its meaning through clear names and structure. Leave comments tied to untouched code unchanged. Keep comment cleanup inside the requested task.
119
- - Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed rather than added or justified.
119
+ - Production and tests follow one rule. Changed directive, TODO, FIXME, HACK, XXX, and type-ignore comments are removed. Do not add or justify them.
120
120
  - Express new explanations through self-documenting names
121
121
  - Docstrings remain allowed.
122
122