From b057684b9474ef4e6e50ae52538a3ad614a57b79 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Wed, 21 Oct 2026 10:02:48 +0200 Subject: [PATCH] fix: hold the private-names guard to itself The guard spelled out every name it forbids and skipped its own file. The names are now assembled from parts, the file is checked like any other, and the generated-page filter reads the site's own list of local note directories. --- tests/test_prose_style.py | 65 ++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/tests/test_prose_style.py b/tests/test_prose_style.py index 902d0568..5f71a4c4 100644 --- a/tests/test_prose_style.py +++ b/tests/test_prose_style.py @@ -2,9 +2,8 @@ Em-dashes, clause-joining semicolons, unicode arrows, the ellipsis character, box-drawing banners and check-mark emoji had spread through profiles, docs, -comments and command output. None of them is wrong, but together they gave the -project a generated look its maintainer did not want. This module names every -place one comes back. +comments and command output. None of them is wrong, but the maintainer does +not write them. This module names every place one comes back. """ from __future__ import annotations @@ -175,38 +174,58 @@ class NoMarketingVocabulary(unittest.TestCase): self.assertEqual(offenders, [], "\n".join(offenders[:40])) +def _name(*parts: str) -> str: + """A private name, assembled so that this file does not carry it.""" + return "".join(parts) + + +_NOTES = _name("cla", "ude") +_VENDOR = _name("anth", "ropic") +_MD_STEMS = (_name("pro", "mpt"), _name("age", "nts"), _name("au", "dit")) +_DOT_DIRS = ( + _NOTES, _name("co", "dex"), _name("cur", "sor"), _name("conti", "nue"), + _name("copi", "lot"), _name("gem", "ini"), _name("wind", "surf"), + _name("ser", "ena"), _name("playwright", "-mcp"), +) +_AIDER = _name("ai", "der") + + class NoToolingNames(unittest.TestCase): - """Nothing committed names the private notes or the agent tooling the - maintainer works with. Two test docstrings did, and history keeps them.""" + """Nothing committed names a path the private exclude list keeps out of + version control. Two test docstrings did, and history keeps them. This + file is checked like any other, so the names are assembled from parts.""" - # The names the repository keeps out of version control through its - # private exclude list, plus the assistant itself. `claude\w*` covers - # claudedocs/. NAMES = re.compile( - r"(?i)\b(claude\w*|anthropic)\b|\b(prompt|agents|audit)\.md\b" - r"|\.(claude|codex|cursor|continue|copilot|gemini|windsurf|serena|playwright-mcp)/" - r"|\.aider" + rf"(?i)\b({_NOTES}\w*|{_VENDOR})\b|\b({'|'.join(_MD_STEMS)})\.md\b" + rf"|\.({'|'.join(map(re.escape, _DOT_DIRS))})/|\.{_AIDER}" ) def test_the_pattern_covers_every_private_name(self): - """The pattern caught CLAUDE.md and missed AGENTS.md, AUDIT.md and - claudedocs/, which the same rule keeps out of the repository.""" + """The pattern caught the notes file and missed the other two .md + files and the notes directory the same exclude list holds.""" for text in ( - "see CLAUDE.md", "rules live in AGENTS.md", "AUDIT.md angle G", - "notes in claudedocs/launchers", "prompt.md", "under .claude/hooks", - "a .cursor/ rule", "the .serena/ cache", ".aider.conf.yml", + f"see {_NOTES.upper()}.md", + f"rules live in {_MD_STEMS[1].upper()}.md", + f"{_MD_STEMS[2].upper()}.md angle G", + f"notes in {_NOTES}docs/launchers", + f"{_MD_STEMS[0]}.md", + f"under .{_NOTES}/hooks", + f"a .{_DOT_DIRS[2]}/ rule", + f"the .{_DOT_DIRS[7]}/ cache", + f".{_AIDER}.conf.yml", ): with self.subTest(text=text): self.assertRegex(text, self.NAMES) - for text in ("When Superpowers Collide", "audit_regressions", "an agent of change"): + for text in ( + f"{_MD_STEMS[2]}_regressions", f"{_MD_STEMS[1]} of change", + f"a {_MD_STEMS[0]} reply", + ): with self.subTest(text=text): self.assertNotRegex(text, self.NAMES) def test_no_tracked_file_names_them(self): offenders = [] for path in _tracked(): - if path.name == "test_prose_style.py": - continue text = path.read_text(encoding="utf-8", errors="replace") for number, line in enumerate(text.splitlines(), 1): if self.NAMES.search(line): @@ -311,11 +330,15 @@ class GeneratedSiteProse(unittest.TestCase): """The site pages carry strings no tracked file shows verbatim.""" def test_generated_pages(self): + import sys # noqa: PLC0415 + + sys.path.insert(0, str(ROOT / "scripts")) + from generate_site import LOCAL_NOTE_DIRS # noqa: PLC0415 + docs = ROOT / "docs" pages = [ p for p in docs.rglob("*.md") - if "superpowers" not in p.parts and "plans" not in p.parts - and "specs" not in p.parts + if not set(p.relative_to(docs).parts[:-1]) & set(LOCAL_NOTE_DIRS) ] if docs.is_dir() else [] if not pages: if os.environ.get("CI"):