"""Regression test for task path conventions in prompts and templates.""" import re from pathlib import Path import pytest ROOT = Path(__file__).resolve().parent.parent PROMPTS_DIR = ROOT / "prompts" TEMPLATES_DIR = ROOT / "templates" # Legacy path pattern that should no longer appear (with placeholder). LEGACY_PATH = re.compile(r"\{project\}/tasks/\{task-name\}/") # Canonical path pattern that should be used instead. CANONICAL_PATH = re.compile(r"\{project\}/\.automaton/tasks/\{task-name\}/") # Concrete legacy path pattern: {project}/tasks/ followed by any name. # Catches paths like {project}/tasks/onboarding/ that use concrete names. CONCRETE_LEGACY_PATH = re.compile(r"\{project\}/tasks/[\w-]+/") def _markdown_files(*directories: Path) -> list[Path]: files = [] for directory in directories: if directory.exists(): files.extend(directory.rglob("*.md")) return files @pytest.mark.parametrize("path", _markdown_files(PROMPTS_DIR, TEMPLATES_DIR)) def test_no_legacy_task_paths(path: Path) -> None: """Every prompt/template must use the canonical .automaton/tasks path.""" text = path.read_text(encoding="utf-8") legacy_matches = LEGACY_PATH.findall(text) assert not legacy_matches, ( f"Found legacy task path in {path.relative_to(ROOT)}: {legacy_matches}\n" "Use {project}/.automaton/tasks/{task-name}/ instead." ) @pytest.mark.parametrize("path", _markdown_files(PROMPTS_DIR, TEMPLATES_DIR)) def test_no_concrete_legacy_task_paths(path: Path) -> None: """Every prompt/template must not use {project}/tasks/ with concrete task names.""" text = path.read_text(encoding="utf-8") # Exclude the migration detection reference, which legitimately mentions the deprecated path. concrete_matches = CONCRETE_LEGACY_PATH.findall(text) # Filter out the onboarding migration detection section that references the legacy path. if concrete_matches and "Migration Check" in text: lines = text.splitlines() filtered = [] in_migration = False for line in lines: if "Migration Check" in line or "Migration Detection" in line: in_migration = True if in_migration and line.startswith("#") and "Migration" not in line: in_migration = False if not in_migration: for m in CONCRETE_LEGACY_PATH.findall(line): filtered.append(m) concrete_matches = filtered assert not concrete_matches, ( f"Found concrete legacy task path in {path.relative_to(ROOT)}: {concrete_matches}\n" "Use {project}/.automaton/tasks/ instead of {project}/tasks/." ) def test_canonical_path_present_in_prompts() -> None: """At least one prompt uses the canonical path (sanity check).""" found = False for path in _markdown_files(PROMPTS_DIR): if CANONICAL_PATH.search(path.read_text(encoding="utf-8")): found = True break assert found, "No prompt uses the canonical {project}/.automaton/tasks/{task-name}/ path"