claude-dev-env 8.12.0 → 8.13.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/.agents/skills/pull-request/scripts/test_pull_request.py +1 -1
- package/.agents/skills-archived/pr-converge/scripts/test_check_convergence.py +4 -4
- package/_shared/advisor/reference/astra-rung.md +7 -7
- package/_shared/advisor/reference/third-party-bind.md +2 -2
- package/_shared/advisor/scripts/codex_astra_advisor.py +33 -26
- package/_shared/advisor/scripts/codex_astra_preflight.py +57 -55
- package/_shared/advisor/scripts/config/advisor_scripts_constants/astra_advisor_constants.py +8 -8
- package/_shared/advisor/scripts/tests/test_codex_astra_advisor.py +69 -23
- package/_shared/advisor/scripts/tests/test_codex_astra_preflight.py +4 -4
- package/_shared/pr-loop/scripts/check_convergence.py +54 -49
- package/_shared/pr-loop/scripts/codex_review_scripts_constants/run_constants.py +4 -0
- package/_shared/pr-loop/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +10 -1
- package/_shared/pr-loop/scripts/run_codex_review.py +4 -6
- package/_shared/pr-loop/scripts/test_check_convergence.py +6 -6
- package/_shared/pr-loop/scripts/test_check_convergence_codex.py +73 -31
- package/_shared/pr-loop/scripts/test_check_convergence_contract.py +2 -2
- package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +2 -2
- package/bin/git_hooks_installer.test.mjs +1 -1
- package/bin/install-constants.mjs +1 -6
- package/bin/install.cursor-rules.test.mjs +24 -51
- package/bin/install.mjs +16 -70
- package/docs/codex-accounts.md +79 -0
- package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +5 -5
- package/hooks/blocking/test_pii_scanner.py +1 -1
- package/hooks/blocking/test_pytest_testpaths_orphan_blocker.py +2 -2
- package/hooks/git-hooks/conftest.py +16 -0
- package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +1 -1
- package/hooks/git-hooks/test_post_commit.py +1 -1
- package/hooks/git-hooks/test_pre_commit.py +1 -1
- package/hooks/git-hooks/test_pre_push.py +2 -2
- package/hooks/git-hooks/test_verification_start.py +1 -1
- package/hooks/git-hooks/verification_notice.py +2 -2
- package/hooks/git-hooks/verification_notice_context.py +21 -2
- package/hooks/git-hooks/verification_start.py +2 -3
- package/package.json +1 -1
- package/rules/durable-post-artifacts.md +4 -3
- package/scripts/claude_account_profile.py +21 -9
- package/scripts/codex_account_choice.py +396 -0
- package/scripts/codex_account_meters.py +372 -0
- package/scripts/dev_env_scripts_constants/codex_account_constants.py +141 -0
- package/scripts/dev_env_scripts_constants/private_term_constants.py +17 -2
- package/scripts/private_term_scan.py +6 -2
- package/scripts/repository_checks/config/constants.py +1 -0
- package/scripts/repository_checks/tracked_private_terms.py +7 -0
- package/scripts/test_claude_account_profile.py +12 -0
- package/scripts/test_codex_account_choice.py +276 -0
- package/scripts/test_codex_account_meters.py +205 -0
- package/scripts/tests/test_automatic_advisory.py +3 -3
- package/scripts/tests/test_automatic_advisory_polling.py +1 -1
- package/scripts/tests/test_automatic_advisory_recovery.py +1 -1
- package/scripts/tests/test_closed_pr_label.py +1 -1
- package/scripts/tests/test_private_term_scan.py +28 -0
- package/scripts/tests/test_review_closure.py +2 -2
- package/scripts/tests/test_review_closure_model.py +2 -2
- package/scripts/tests/test_rules.py +2 -83
- package/scripts/tests/test_tracked_private_terms.py +15 -0
- package/scripts/tests/test_verification_notice.py +29 -13
- package/.agents/skills/cert-classification-rule/SKILL.md +0 -224
- package/.agents/skills/cert-classification-rule/scripts/resort_cert_folders.py +0 -158
- package/_shared/pr-loop/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +0 -82
- package/_shared/pr-loop/scripts/codex_usage_probe.py +0 -573
- package/_shared/pr-loop/scripts/test_codex_usage_probe.py +0 -683
- package/scripts/sync_to_cursor/AGENTS.md +0 -1
- package/scripts/sync_to_cursor/CLAUDE.md +0 -1
- package/scripts/sync_to_cursor/__init__.py +0 -13
- package/scripts/sync_to_cursor/canonical_docs.py +0 -66
- package/scripts/sync_to_cursor/config/__init__.py +0 -8
- package/scripts/sync_to_cursor/engine.py +0 -219
- package/scripts/sync_to_cursor/hashing.py +0 -7
- package/scripts/sync_to_cursor/paths.py +0 -18
- package/scripts/sync_to_cursor/rules.py +0 -494
- package/scripts/sync_to_cursor.py +0 -22
- package/scripts/tests/test_engine.py +0 -101
- package/scripts/tests/test_sync_to_cursor.py +0 -315
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
"""Tests for sync_to_cursor.py: canonical docs copy, manifest, and truncation footer."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
import pytest
|
|
10
|
-
|
|
11
|
-
_SCRIPTS_DIR = Path(__file__).resolve().parent.parent
|
|
12
|
-
if str(_SCRIPTS_DIR) not in sys.path:
|
|
13
|
-
sys.path.insert(0, str(_SCRIPTS_DIR))
|
|
14
|
-
|
|
15
|
-
import sync_to_cursor as mod
|
|
16
|
-
from sync_to_cursor.engine import run as run_sync_to_cursor
|
|
17
|
-
from sync_to_cursor.rules import (
|
|
18
|
-
_code_standards_section_order,
|
|
19
|
-
_parse_h2_sections,
|
|
20
|
-
_read_paths_glob,
|
|
21
|
-
_test_quality_section_order,
|
|
22
|
-
build_mappings,
|
|
23
|
-
strip_leading_yaml_frontmatter,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
_CLAUDE_DEV_ENV_DIR = _SCRIPTS_DIR.parent
|
|
27
|
-
_REAL_TESTING_RULE = _CLAUDE_DEV_ENV_DIR / "rules" / "testing.md"
|
|
28
|
-
_REAL_CODE_RULES_DOC = _CLAUDE_DEV_ENV_DIR / "docs" / "CODE_RULES.md"
|
|
29
|
-
_REAL_TEST_QUALITY_DOC = _CLAUDE_DEV_ENV_DIR / "docs" / "TEST_QUALITY.md"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _minimal_rule_files(claude_rules: Path) -> None:
|
|
33
|
-
claude_rules.mkdir(parents=True, exist_ok=True)
|
|
34
|
-
(claude_rules / "code-standards.md").write_text(
|
|
35
|
-
"# Code standards stub\n", encoding="utf-8"
|
|
36
|
-
)
|
|
37
|
-
(claude_rules / "tasklings-preferences.md").write_text(
|
|
38
|
-
"---\npaths:\n - \"Y:/x/**\"\n---\n\n# Tasklings\n",
|
|
39
|
-
encoding="utf-8",
|
|
40
|
-
)
|
|
41
|
-
(claude_rules / "bdd.md").write_text("# BDD\n", encoding="utf-8")
|
|
42
|
-
(claude_rules / "testing.md").write_text(
|
|
43
|
-
"---\npaths:\n - \"**/test_*.py\"\n---\n\n# Testing\n",
|
|
44
|
-
encoding="utf-8",
|
|
45
|
-
)
|
|
46
|
-
(claude_rules / "research-mode.md").write_text("# RM\n", encoding="utf-8")
|
|
47
|
-
(claude_rules / "explore-thoroughly.md").write_text("# ET\n", encoding="utf-8")
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def _minimal_code_rules_and_test_quality(claude_docs: Path) -> tuple[bytes, bytes]:
|
|
51
|
-
claude_docs.mkdir(parents=True, exist_ok=True)
|
|
52
|
-
cr = (
|
|
53
|
-
"\n\n".join(f"## {title}\n\nalpha" for title in _code_standards_section_order) + "\n"
|
|
54
|
-
).encode("utf-8")
|
|
55
|
-
tq = (
|
|
56
|
-
"\n\n".join(f"## {title}\n\nbeta" for title in _test_quality_section_order) + "\n"
|
|
57
|
-
).encode("utf-8")
|
|
58
|
-
(claude_docs / "CODE_RULES.md").write_bytes(cr)
|
|
59
|
-
(claude_docs / "TEST_QUALITY.md").write_bytes(tq)
|
|
60
|
-
return cr, tq
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def test_limit_lines_footer_mentions_cursor_docs() -> None:
|
|
64
|
-
long_body = "\n".join(f"line {index}" for index in range(mod.MAX_RULE_BODY_LINES + 5))
|
|
65
|
-
out = mod._limit_lines(long_body, mod.MAX_RULE_BODY_LINES)
|
|
66
|
-
assert ".cursor/docs" in out
|
|
67
|
-
assert "synced reference" in out
|
|
68
|
-
assert "~/.claude/system-prompts/software-engineer.xml" in out
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_sync_canonical_docs_copies_byte_identical(tmp_path: Path) -> None:
|
|
72
|
-
claude = tmp_path / ".claude"
|
|
73
|
-
cursor = tmp_path / ".cursor"
|
|
74
|
-
docs = claude / "docs"
|
|
75
|
-
cr, tq = _minimal_code_rules_and_test_quality(docs)
|
|
76
|
-
mod._sync_canonical_docs(claude, cursor, dry_run=False, quiet=True)
|
|
77
|
-
assert (cursor / "docs" / "CODE_RULES.md").read_bytes() == cr
|
|
78
|
-
assert (cursor / "docs" / "TEST_QUALITY.md").read_bytes() == tq
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def test_sync_canonical_docs_skips_missing_with_no_dst(tmp_path: Path) -> None:
|
|
82
|
-
claude = tmp_path / ".claude"
|
|
83
|
-
cursor = tmp_path / ".cursor"
|
|
84
|
-
(claude / "docs").mkdir(parents=True)
|
|
85
|
-
(claude / "docs" / "CODE_RULES.md").write_text("x", encoding="utf-8")
|
|
86
|
-
mod._sync_canonical_docs(claude, cursor, dry_run=False, quiet=True)
|
|
87
|
-
assert (cursor / "docs" / "CODE_RULES.md").read_text(encoding="utf-8") == "x"
|
|
88
|
-
assert not (cursor / "docs" / "TEST_QUALITY.md").is_file()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def test_check_fails_when_doc_source_changes_without_resync(
|
|
92
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
93
|
-
) -> None:
|
|
94
|
-
claude = tmp_path / ".claude"
|
|
95
|
-
_minimal_rule_files(claude / "rules")
|
|
96
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
97
|
-
monkeypatch.setenv("LLM_SETTINGS_ROOT", str(tmp_path))
|
|
98
|
-
assert run_sync_to_cursor(["--force"]) == 0
|
|
99
|
-
(claude / "docs" / "CODE_RULES.md").write_bytes(b"changed\n")
|
|
100
|
-
assert run_sync_to_cursor(["--check"]) != 0
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def test_check_passes_after_resync(
|
|
104
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
105
|
-
) -> None:
|
|
106
|
-
claude = tmp_path / ".claude"
|
|
107
|
-
_minimal_rule_files(claude / "rules")
|
|
108
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
109
|
-
monkeypatch.setenv("LLM_SETTINGS_ROOT", str(tmp_path))
|
|
110
|
-
assert run_sync_to_cursor(["--force"]) == 0
|
|
111
|
-
assert run_sync_to_cursor(["--check"]) == 0
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def test_manifest_includes_docs_entries(
|
|
115
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
116
|
-
) -> None:
|
|
117
|
-
claude = tmp_path / ".claude"
|
|
118
|
-
cursor = tmp_path / ".cursor"
|
|
119
|
-
_minimal_rule_files(claude / "rules")
|
|
120
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
121
|
-
monkeypatch.setenv("LLM_SETTINGS_ROOT", str(tmp_path))
|
|
122
|
-
assert run_sync_to_cursor(["--force"]) == 0
|
|
123
|
-
manifest = json.loads((cursor / ".sync-manifest.json").read_text(encoding="utf-8"))
|
|
124
|
-
assert "docs_entries" in manifest
|
|
125
|
-
docs_entries = manifest["docs_entries"]
|
|
126
|
-
assert "docs/CODE_RULES.md" in docs_entries
|
|
127
|
-
assert "docs/TEST_QUALITY.md" in docs_entries
|
|
128
|
-
assert "sources_hash" in docs_entries["docs/CODE_RULES.md"]
|
|
129
|
-
assert "output_hash" in docs_entries["docs/CODE_RULES.md"]
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def test_merge_code_standards_with_pointer_style_code_rules(tmp_path: Path) -> None:
|
|
133
|
-
rules_directory = tmp_path / "rules"
|
|
134
|
-
docs_directory = tmp_path / "docs"
|
|
135
|
-
rules_directory.mkdir(parents=True, exist_ok=True)
|
|
136
|
-
docs_directory.mkdir(parents=True, exist_ok=True)
|
|
137
|
-
(rules_directory / "code-standards.md").write_text(
|
|
138
|
-
"# Code standards stub\n\n- Use full words\n", encoding="utf-8"
|
|
139
|
-
)
|
|
140
|
-
(docs_directory / "CODE_RULES.md").write_text(
|
|
141
|
-
"# CODE_RULES pointer: canonical code-quality policy lives in"
|
|
142
|
-
" `~/.claude/system-prompts/software-engineer.xml` under `<code_quality>`.\n",
|
|
143
|
-
encoding="utf-8",
|
|
144
|
-
)
|
|
145
|
-
merged = mod.merge_code_standards(
|
|
146
|
-
(rules_directory / "code-standards.md", docs_directory / "CODE_RULES.md")
|
|
147
|
-
)
|
|
148
|
-
assert merged.strip(), "output must not be empty for pointer-style CODE_RULES.md"
|
|
149
|
-
assert "software-engineer.xml" in merged
|
|
150
|
-
assert "code_quality" in merged
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def test_sync_canonical_docs_deletes_stale_copy_when_source_removed(tmp_path: Path) -> None:
|
|
154
|
-
claude = tmp_path / ".claude"
|
|
155
|
-
cursor = tmp_path / ".cursor"
|
|
156
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
157
|
-
mod._sync_canonical_docs(claude, cursor, dry_run=False, quiet=True)
|
|
158
|
-
assert (cursor / "docs" / "CODE_RULES.md").is_file()
|
|
159
|
-
(claude / "docs" / "CODE_RULES.md").unlink()
|
|
160
|
-
mod._sync_canonical_docs(claude, cursor, dry_run=False, quiet=True)
|
|
161
|
-
assert not (cursor / "docs" / "CODE_RULES.md").is_file()
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def test_dry_run_does_not_create_output_directory(
|
|
165
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
166
|
-
) -> None:
|
|
167
|
-
claude = tmp_path / ".claude"
|
|
168
|
-
cursor = tmp_path / ".cursor"
|
|
169
|
-
_minimal_rule_files(claude / "rules")
|
|
170
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
171
|
-
monkeypatch.setenv("LLM_SETTINGS_ROOT", str(tmp_path))
|
|
172
|
-
assert run_sync_to_cursor(["--dry-run", "--quiet"]) == 0
|
|
173
|
-
assert not (cursor / "rules").exists(), "--dry-run must not create the output directory"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def test_check_skips_optional_mapping_when_source_missing(
|
|
177
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
178
|
-
) -> None:
|
|
179
|
-
claude = tmp_path / ".claude"
|
|
180
|
-
_minimal_rule_files(claude / "rules")
|
|
181
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
182
|
-
monkeypatch.setenv("LLM_SETTINGS_ROOT", str(tmp_path))
|
|
183
|
-
assert run_sync_to_cursor(["--force"]) == 0
|
|
184
|
-
(claude / "rules" / "tasklings-preferences.md").unlink()
|
|
185
|
-
assert run_sync_to_cursor(["--check"]) == 0, "--check must pass when only optional sources are missing"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def test_test_quality_glob_derived_from_testing_frontmatter() -> None:
|
|
189
|
-
expected_glob = _read_paths_glob(_REAL_TESTING_RULE)
|
|
190
|
-
assert expected_glob, "testing.md must declare a non-empty paths frontmatter"
|
|
191
|
-
pinned_glob = "**/test_*.py,**/*_test.py,**/*.test.*,**/*.spec.*,**/conftest.py,**/tests/**"
|
|
192
|
-
assert expected_glob == pinned_glob
|
|
193
|
-
test_quality_mapping = next(
|
|
194
|
-
mapping for mapping in build_mappings(_CLAUDE_DEV_ENV_DIR) if mapping.key == "test-quality"
|
|
195
|
-
)
|
|
196
|
-
assert test_quality_mapping.globs == expected_glob
|
|
197
|
-
assert test_quality_mapping.globs == pinned_glob
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def test_tasklings_glob_derived_from_frontmatter(tmp_path: Path) -> None:
|
|
201
|
-
rules_directory = tmp_path / "rules"
|
|
202
|
-
rules_directory.mkdir(parents=True)
|
|
203
|
-
(rules_directory / "tasklings-preferences.md").write_text(
|
|
204
|
-
'---\npaths:\n - "Y:/MyProject/**"\n - "Z:/Other/**"\n---\n\n# Tasklings\n',
|
|
205
|
-
encoding="utf-8",
|
|
206
|
-
)
|
|
207
|
-
glob_value = _read_paths_glob(rules_directory / "tasklings-preferences.md")
|
|
208
|
-
assert glob_value == "Y:/MyProject/**,Z:/Other/**"
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def test_merge_reference_headers_point_at_cursor_docs(tmp_path: Path) -> None:
|
|
212
|
-
rules_directory = tmp_path / "rules"
|
|
213
|
-
docs_directory = tmp_path / "docs"
|
|
214
|
-
rules_directory.mkdir(parents=True, exist_ok=True)
|
|
215
|
-
docs_directory.mkdir(parents=True, exist_ok=True)
|
|
216
|
-
(rules_directory / "code-standards.md").write_text("# CS\n", encoding="utf-8")
|
|
217
|
-
cr_body = "\n\n".join(f"## {t}\n\nbody" for t in _code_standards_section_order)
|
|
218
|
-
(docs_directory / "CODE_RULES.md").write_text(cr_body, encoding="utf-8")
|
|
219
|
-
merged = mod.merge_code_standards(
|
|
220
|
-
(rules_directory / "code-standards.md", docs_directory / "CODE_RULES.md")
|
|
221
|
-
)
|
|
222
|
-
assert ".cursor/docs/CODE_RULES.md" in merged
|
|
223
|
-
|
|
224
|
-
(rules_directory / "testing.md").write_text("# T\n", encoding="utf-8")
|
|
225
|
-
tq_body = "\n\n".join(f"## {t}\n\nbody" for t in _test_quality_section_order)
|
|
226
|
-
(docs_directory / "TEST_QUALITY.md").write_text(tq_body, encoding="utf-8")
|
|
227
|
-
merged_tq = mod.merge_test_quality(
|
|
228
|
-
(rules_directory / "testing.md", docs_directory / "TEST_QUALITY.md")
|
|
229
|
-
)
|
|
230
|
-
assert ".cursor/docs/TEST_QUALITY.md" in merged_tq
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
def test_code_standards_section_order_titles_all_exist_in_real_doc() -> None:
|
|
234
|
-
real_headings = set(_parse_h2_sections(_REAL_CODE_RULES_DOC.read_text(encoding="utf-8")))
|
|
235
|
-
missing_titles = [title for title in _code_standards_section_order if title not in real_headings]
|
|
236
|
-
assert missing_titles == [], (
|
|
237
|
-
f"_code_standards_section_order titles absent from {_REAL_CODE_RULES_DOC.name}: "
|
|
238
|
-
f"{missing_titles}"
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
def test_test_quality_section_order_titles_all_exist_in_real_doc() -> None:
|
|
243
|
-
real_headings = set(_parse_h2_sections(_REAL_TEST_QUALITY_DOC.read_text(encoding="utf-8")))
|
|
244
|
-
missing_titles = [title for title in _test_quality_section_order if title not in real_headings]
|
|
245
|
-
assert missing_titles == [], (
|
|
246
|
-
f"_test_quality_section_order titles absent from {_REAL_TEST_QUALITY_DOC.name}: "
|
|
247
|
-
f"{missing_titles}"
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
def test_merge_code_standards_raises_when_expected_section_absent(tmp_path: Path) -> None:
|
|
252
|
-
rules_directory = tmp_path / "rules"
|
|
253
|
-
docs_directory = tmp_path / "docs"
|
|
254
|
-
rules_directory.mkdir(parents=True, exist_ok=True)
|
|
255
|
-
docs_directory.mkdir(parents=True, exist_ok=True)
|
|
256
|
-
(rules_directory / "code-standards.md").write_text("# CS\n", encoding="utf-8")
|
|
257
|
-
present_titles = [
|
|
258
|
-
title for title in _code_standards_section_order if title != "5. NO ABBREVIATIONS"
|
|
259
|
-
]
|
|
260
|
-
cr_body = "\n\n".join(f"## {title}\n\nbody" for title in present_titles)
|
|
261
|
-
(docs_directory / "CODE_RULES.md").write_text(cr_body, encoding="utf-8")
|
|
262
|
-
with pytest.raises(AssertionError, match="5. NO ABBREVIATIONS"):
|
|
263
|
-
mod.merge_code_standards(
|
|
264
|
-
(rules_directory / "code-standards.md", docs_directory / "CODE_RULES.md")
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
def test_build_mappings_raises_when_testing_lacks_paths_frontmatter(tmp_path: Path) -> None:
|
|
269
|
-
claude = tmp_path / ".claude"
|
|
270
|
-
_minimal_rule_files(claude / "rules")
|
|
271
|
-
_minimal_code_rules_and_test_quality(claude / "docs")
|
|
272
|
-
(claude / "rules" / "testing.md").write_text("# Testing\n", encoding="utf-8")
|
|
273
|
-
with pytest.raises(AssertionError, match="testing.md"):
|
|
274
|
-
build_mappings(claude)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def test_merge_test_quality_raises_when_expected_section_absent(tmp_path: Path) -> None:
|
|
278
|
-
rules_directory = tmp_path / "rules"
|
|
279
|
-
docs_directory = tmp_path / "docs"
|
|
280
|
-
rules_directory.mkdir(parents=True, exist_ok=True)
|
|
281
|
-
docs_directory.mkdir(parents=True, exist_ok=True)
|
|
282
|
-
(rules_directory / "testing.md").write_text("# T\n", encoding="utf-8")
|
|
283
|
-
present_titles = [
|
|
284
|
-
title for title in _test_quality_section_order if title != "Core Testing Principles"
|
|
285
|
-
]
|
|
286
|
-
tq_body = "\n\n".join(f"## {title}\n\nbody" for title in present_titles)
|
|
287
|
-
(docs_directory / "TEST_QUALITY.md").write_text(tq_body, encoding="utf-8")
|
|
288
|
-
with pytest.raises(AssertionError, match="Core Testing Principles"):
|
|
289
|
-
mod.merge_test_quality(
|
|
290
|
-
(rules_directory / "testing.md", docs_directory / "TEST_QUALITY.md")
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
def test_merge_test_quality_strips_leading_paths_frontmatter(tmp_path: Path) -> None:
|
|
295
|
-
docs_directory = tmp_path / "docs"
|
|
296
|
-
docs_directory.mkdir(parents=True, exist_ok=True)
|
|
297
|
-
test_quality_body = "\n\n".join(
|
|
298
|
-
f"## {title}\n\nbody" for title in _test_quality_section_order
|
|
299
|
-
)
|
|
300
|
-
(docs_directory / "TEST_QUALITY.md").write_text(test_quality_body, encoding="utf-8")
|
|
301
|
-
merged = mod.merge_test_quality(
|
|
302
|
-
(_REAL_TESTING_RULE, docs_directory / "TEST_QUALITY.md")
|
|
303
|
-
)
|
|
304
|
-
testing_text = _REAL_TESTING_RULE.read_text(encoding="utf-8")
|
|
305
|
-
first_content_line = next(
|
|
306
|
-
line for line in strip_leading_yaml_frontmatter(testing_text).splitlines()
|
|
307
|
-
if line.strip()
|
|
308
|
-
)
|
|
309
|
-
merged_lines = merged.splitlines()
|
|
310
|
-
assert merged_lines[0] != "---", "merged body must not open with a leaked frontmatter fence"
|
|
311
|
-
assert merged_lines[0] == first_content_line
|
|
312
|
-
body_before_reference = "\n".join(
|
|
313
|
-
merged_lines[: merged_lines.index("## Reference (full text: `.cursor/docs/TEST_QUALITY.md`)")]
|
|
314
|
-
)
|
|
315
|
-
assert "paths:" not in body_before_reference, "testing.md paths frontmatter leaked into rule body"
|