From 8928f6d3ab430bdd49d89147d359e0a48f125d4b Mon Sep 17 00:00:00 2001 From: Original Gary <276612211+OpenGaryBot@users.noreply.github.com> Date: Fri, 1 May 2026 23:36:18 +1000 Subject: [PATCH 1/3] test(#47): add failing tests for open-PR dedup rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [worktree:scai-dedup] Seven tests encode the behavioural contract: dedup rule present in all 10 target files, gh pr list command present, halt instruction present, reroute option present, orchestrator-mode.md Process Enforcement section has the open-PR rule, unicode integrity clean, no speciesist language. All tests fail before implementation — correct TDD start state. --- scripts/tests/test_dedup_rule.py | 248 +++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 scripts/tests/test_dedup_rule.py diff --git a/scripts/tests/test_dedup_rule.py b/scripts/tests/test_dedup_rule.py new file mode 100644 index 0000000..22862a3 --- /dev/null +++ b/scripts/tests/test_dedup_rule.py @@ -0,0 +1,248 @@ +""" +Tests for the open-PR de-duplication rule inserted at Step 0 of git-workflow +instruction files and in kilo-code/orchestrator-mode.md. + +Behaviour under test: an agent following Step 0 of git-workflow MUST halt before +dispatching planner work when an open PR already references the target issue. + +All assertions encode domain rules and are mutation-resistant: deleting or +softening the rule text in ANY target file will fail the corresponding test. +""" + +import subprocess +import sys +from pathlib import Path + +import pytest + +# --------------------------------------------------------------------------- +# Repo root — tests run from the repo root or from anywhere via pytest discovery +# --------------------------------------------------------------------------- + +REPO_ROOT = Path(__file__).resolve().parents[2] + +# --------------------------------------------------------------------------- +# The 10 target files that must carry the dedup rule +# --------------------------------------------------------------------------- + +GIT_WORKFLOW_FILES = [ + REPO_ROOT / "claude-code" / ".claude" / "skills" / "git-workflow" / "SKILL.md", + REPO_ROOT / "kilo-code" / ".kilocode" / "skills" / "git-workflow" / "SKILL.md", + REPO_ROOT / "github-copilot" / ".github" / "skills" / "git-workflow" / "SKILL.md", + REPO_ROOT / "augment-code" / ".augment" / "rules" / "git-workflow.md", + REPO_ROOT / "cline" / ".clinerules" / "git-workflow.md", + REPO_ROOT / "cursor" / ".cursor" / "rules" / "git-workflow.mdc", + REPO_ROOT / "windsurf" / ".windsurf" / "rules" / "git-workflow.md", + REPO_ROOT / "roo-code" / ".roo" / "rules" / "git-workflow.md", + REPO_ROOT / "agents-md" / "AGENTS.md", +] + +ORCHESTRATOR_MODE_FILE = ( + REPO_ROOT / "kilo-code" / ".kilocode" / "rules" / "orchestrator-mode.md" +) + +ALL_CHANGED_FILES = GIT_WORKFLOW_FILES + [ORCHESTRATOR_MODE_FILE] + +# --------------------------------------------------------------------------- +# Canonical strings that MUST appear in every target file +# --------------------------------------------------------------------------- + +# The executable command string (not the full bash block, just the identifiable part) +GH_PR_LIST_COMMAND = "gh pr list --state open" + +# The halt / no-duplicate-PR instruction +HALT_INSTRUCTION = "Do not open a new PR" + +# The reroute option +REROUTE_INSTRUCTION = "plan-reviewer" + + +# --------------------------------------------------------------------------- +# Helper +# --------------------------------------------------------------------------- + +def read_text(path: Path) -> str: + return path.read_text(encoding="utf-8") + + +# --------------------------------------------------------------------------- +# Test 1: dedup rule block is present in all target files +# +# Behaviour: the dedup rule exists in every tool instruction surface. +# Mutation kill: deleting the block from any file fails this test. +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize("filepath", ALL_CHANGED_FILES, ids=[p.name for p in ALL_CHANGED_FILES]) +def test_dedup_rule_present(filepath: Path) -> None: + """Every target file must contain the open-PR dedup rule.""" + assert filepath.exists(), f"File not found: {filepath}" + content = read_text(filepath) + assert "Open PR already exists" in content or "open PR" in content.lower(), ( + f"Dedup rule not found in {filepath.relative_to(REPO_ROOT)}\n" + "Expected text signalling the open-PR check (e.g. 'Open PR already exists')" + ) + + +# --------------------------------------------------------------------------- +# Test 2: the gh pr list command is present in all git-workflow files +# +# Behaviour: the check is executable — an agent can copy/run the command. +# Mutation kill: removing the command string fails this test. +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize("filepath", ALL_CHANGED_FILES, ids=[p.name for p in ALL_CHANGED_FILES]) +def test_dedup_rule_contains_gh_pr_list_command(filepath: Path) -> None: + """Every target file must contain the gh pr list --state open command.""" + assert filepath.exists(), f"File not found: {filepath}" + content = read_text(filepath) + assert GH_PR_LIST_COMMAND in content, ( + f"'{GH_PR_LIST_COMMAND}' not found in {filepath.relative_to(REPO_ROOT)}\n" + "The dedup rule must include an executable gh pr list command." + ) + + +# --------------------------------------------------------------------------- +# Test 3: the halt instruction is present in all target files +# +# Behaviour: agents are explicitly directed not to open a duplicate PR. +# Mutation kill: softening "Do not open a new PR" to "consider not opening" +# would fail this test. +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize("filepath", ALL_CHANGED_FILES, ids=[p.name for p in ALL_CHANGED_FILES]) +def test_dedup_rule_contains_halt_instruction(filepath: Path) -> None: + """Every target file must explicitly prohibit opening a new PR when one exists.""" + assert filepath.exists(), f"File not found: {filepath}" + content = read_text(filepath) + assert HALT_INSTRUCTION in content, ( + f"Halt instruction '{HALT_INSTRUCTION}' not found in " + f"{filepath.relative_to(REPO_ROOT)}\n" + "The dedup rule must explicitly state 'Do not open a new PR'." + ) + + +# --------------------------------------------------------------------------- +# Test 4: the reroute option is present in all git-workflow files +# +# Behaviour: agents have a documented reroute path (delegate to plan-reviewer +# with the existing PR as input) rather than only hard-halting. +# Mutation kill: removing the reroute sentence fails this test. +# --------------------------------------------------------------------------- + +@pytest.mark.parametrize("filepath", ALL_CHANGED_FILES, ids=[p.name for p in ALL_CHANGED_FILES]) +def test_dedup_rule_contains_reroute_option(filepath: Path) -> None: + """Every target file must mention rerouting to plan-reviewer with the existing PR.""" + assert filepath.exists(), f"File not found: {filepath}" + content = read_text(filepath) + assert REROUTE_INSTRUCTION in content, ( + f"Reroute instruction '{REROUTE_INSTRUCTION}' not found in " + f"{filepath.relative_to(REPO_ROOT)}\n" + "The dedup rule must document the reroute path to plan-reviewer." + ) + + +# --------------------------------------------------------------------------- +# Test 5: orchestrator-mode.md Process Enforcement section has the open-PR rule +# +# Behaviour: the orchestrator-level enforcement exists independently of the +# per-tool git-workflow files. +# Mutation kill: removing from orchestrator-mode.md only fails THIS test, +# not the parametrised tests above (which also cover that file). +# --------------------------------------------------------------------------- + +def test_orchestrator_mode_contains_open_pr_check() -> None: + """orchestrator-mode.md Process Enforcement section must list the open-PR hard rule.""" + assert ORCHESTRATOR_MODE_FILE.exists(), f"File not found: {ORCHESTRATOR_MODE_FILE}" + content = read_text(ORCHESTRATOR_MODE_FILE) + + # The Process Enforcement section must exist + assert "## Process Enforcement" in content, ( + "orchestrator-mode.md must have a '## Process Enforcement' section." + ) + + # Within that section, the open-PR rule must appear + enforcement_start = content.index("## Process Enforcement") + # Grab everything from that section to the next heading (or end of file) + after_section = content[enforcement_start:] + next_heading = after_section.find("\n## ", 3) + section_body = after_section if next_heading == -1 else after_section[:next_heading] + + assert GH_PR_LIST_COMMAND in section_body, ( + f"'{GH_PR_LIST_COMMAND}' not found in the Process Enforcement section of " + f"orchestrator-mode.md.\n" + "The open-PR check must be a hard rule in the Process Enforcement section." + ) + + +# --------------------------------------------------------------------------- +# Test 6: unicode integrity — no hidden characters in changed files +# +# Behaviour: no zero-width spaces, BIDI overrides, or tag-block characters. +# Mutation kill: injecting a zero-width space (U+200B) into any changed file +# causes the check-unicode-integrity.py script to exit 1. +# --------------------------------------------------------------------------- + +def test_unicode_integrity_all_changed_files() -> None: + """check-unicode-integrity.py must exit 0 for all changed files.""" + script = REPO_ROOT / "scripts" / "check-unicode-integrity.py" + assert script.exists(), f"check-unicode-integrity.py not found at {script}" + + violations = [] + for filepath in ALL_CHANGED_FILES: + if not filepath.exists(): + continue + result = subprocess.run( + [sys.executable, str(script), str(filepath.parent)], + capture_output=True, + text=True, + ) + # The script accepts a directory; filter stdout to lines mentioning this file + file_rel = filepath.name + file_violations = [ + line for line in result.stdout.splitlines() + if file_rel in line and "U+" in line + ] + violations.extend(file_violations) + + assert not violations, ( + "Hidden Unicode characters found in changed files:\n" + + "\n".join(violations) + ) + + +# --------------------------------------------------------------------------- +# Test 7: no speciesist language introduced in changed files +# +# Behaviour: the dedup rule text must not introduce language that normalises +# animal violence (e.g. "kill two birds with one stone"). +# Mutation kill: adding a prohibited idiom to any file fails this test. +# +# Implementation note: requires semgrep + the NAV config. If semgrep is not +# available in the environment, the test is skipped rather than erroring, to +# avoid blocking CI on machines without semgrep installed. +# --------------------------------------------------------------------------- + +SEMGREP_CONFIG = REPO_ROOT / "semgrep-no-animal-violence.yaml" + + +@pytest.mark.skipif( + not SEMGREP_CONFIG.exists(), + reason="semgrep-no-animal-violence.yaml not found — NAV check skipped", +) +def test_no_speciesist_language_introduced() -> None: + """semgrep NAV check must pass on all changed files.""" + semgrep_result = subprocess.run( + [ + "semgrep", + "--config", str(SEMGREP_CONFIG), + "--error", + "--quiet", + ] + [str(f) for f in ALL_CHANGED_FILES if f.exists()], + capture_output=True, + text=True, + ) + assert semgrep_result.returncode == 0, ( + "Speciesist language detected in changed files:\n" + + semgrep_result.stdout + + semgrep_result.stderr + ) From a76ce63b1c2ffea286e69d4ed61d72a03078ffbc Mon Sep 17 00:00:00 2001 From: Original Gary <276612211+OpenGaryBot@users.noreply.github.com> Date: Fri, 1 May 2026 23:39:00 +1000 Subject: [PATCH 2/3] fix(#47): add open-PR dedup check at Step 0 of git-workflow and orchestrator dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before beginning any work on a GitHub issue, agents must now run: gh pr list --state open --search "# in:body,title" If an open PR is returned, agents must not open a new PR and must reroute to plan-reviewer with the existing PR as input instead. This prevents the duplicate PR pairs observed in the 2026-04-26 complexity-cut review. Applied consistently across all 10 instruction surfaces: - claude-code, kilo-code, github-copilot SKILL.md git-workflow files - augment-code, cline, cursor, windsurf, roo-code git-workflow rule files - agents-md/AGENTS.md GitHub Workflow section - kilo-code orchestrator-mode.md Process Enforcement section Tests: 42 passed, 1 skipped (semgrep NAV check skipped — config absent). --- agents-md/AGENTS.md | 2 ++ augment-code/.augment/rules/git-workflow.md | 8 ++++++++ claude-code/.claude/skills/git-workflow/SKILL.md | 8 ++++++++ cline/.clinerules/git-workflow.md | 8 ++++++++ cursor/.cursor/rules/git-workflow.mdc | 8 ++++++++ github-copilot/.github/skills/git-workflow/SKILL.md | 8 ++++++++ kilo-code/.kilocode/rules/orchestrator-mode.md | 1 + kilo-code/.kilocode/skills/git-workflow/SKILL.md | 8 ++++++++ roo-code/.roo/rules/git-workflow.md | 8 ++++++++ scripts/tests/test_dedup_rule.py | 2 +- windsurf/.windsurf/rules/git-workflow.md | 9 +++++++++ 11 files changed, 69 insertions(+), 1 deletion(-) diff --git a/agents-md/AGENTS.md b/agents-md/AGENTS.md index fa35605..c60da9f 100644 --- a/agents-md/AGENTS.md +++ b/agents-md/AGENTS.md @@ -309,6 +309,8 @@ Before starting any coding task on a GitHub repository. Before committing, branc **0. GitHub Issue First.** Before writing any code: `gh issue list --search "keywords"`. If no issue exists, create one with `gh issue create`. Include problem description, acceptance criteria, affected files/components, and security/privacy considerations. Do not begin implementation until the issue is documented. +**Open PR already exists:** After confirming the issue number, check for open PRs that already address it: `gh pr list --state open --search "# in:body,title" --json number,title,url`. If one or more open PRs are returned: **Do not open a new PR** — a duplicate is already in flight. Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. Never open a second PR for the same issue unless the first is explicitly closed. + **1. One Worktree Per Task.** Every task — especially in parallel agent swarms — gets its own git worktree: `git worktree add ../worktrees/ -b `. Branch naming: `fix/-short-description`. When spawning parallel sub-agents, each MUST receive its own unique branch name and worktree path — sharing a branch produces conflicts and corrupted history. **2. Read the Codebase.** Before planning, read every file in the affected module(s), existing utilities and patterns, test files, and recent git log. Do not plan until you can describe the current behavior in your own words. diff --git a/augment-code/.augment/rules/git-workflow.md b/augment-code/.augment/rules/git-workflow.md index 27ce95e..b8d745b 100644 --- a/augment-code/.augment/rules/git-workflow.md +++ b/augment-code/.augment/rules/git-workflow.md @@ -23,6 +23,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/claude-code/.claude/skills/git-workflow/SKILL.md b/claude-code/.claude/skills/git-workflow/SKILL.md index fefc1d7..72d58d1 100644 --- a/claude-code/.claude/skills/git-workflow/SKILL.md +++ b/claude-code/.claude/skills/git-workflow/SKILL.md @@ -27,6 +27,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/cline/.clinerules/git-workflow.md b/cline/.clinerules/git-workflow.md index 3be3074..9414911 100644 --- a/cline/.clinerules/git-workflow.md +++ b/cline/.clinerules/git-workflow.md @@ -23,6 +23,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/cursor/.cursor/rules/git-workflow.mdc b/cursor/.cursor/rules/git-workflow.mdc index 48cfb68..246ceea 100644 --- a/cursor/.cursor/rules/git-workflow.mdc +++ b/cursor/.cursor/rules/git-workflow.mdc @@ -26,6 +26,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/github-copilot/.github/skills/git-workflow/SKILL.md b/github-copilot/.github/skills/git-workflow/SKILL.md index fefc1d7..72d58d1 100644 --- a/github-copilot/.github/skills/git-workflow/SKILL.md +++ b/github-copilot/.github/skills/git-workflow/SKILL.md @@ -27,6 +27,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/kilo-code/.kilocode/rules/orchestrator-mode.md b/kilo-code/.kilocode/rules/orchestrator-mode.md index a71e410..f88650b 100644 --- a/kilo-code/.kilocode/rules/orchestrator-mode.md +++ b/kilo-code/.kilocode/rules/orchestrator-mode.md @@ -64,6 +64,7 @@ Block deployment on any Critical or High severity finding. ## Process Enforcement Orchestrator mode enforces these process rules across all delegated work: +- No planner dispatch without open-PR check: run `gh pr list --state open --search "# in:body,title"` before dispatching for issue N; **Do not open a new PR** if an open PR is found — reroute to plan-reviewer with the existing PR as input instead - No Code mode work without a plan (Architect mode first for significant changes) - No commits without passing tests - No PRs without AI-Assisted tagging diff --git a/kilo-code/.kilocode/skills/git-workflow/SKILL.md b/kilo-code/.kilocode/skills/git-workflow/SKILL.md index fefc1d7..72d58d1 100644 --- a/kilo-code/.kilocode/skills/git-workflow/SKILL.md +++ b/kilo-code/.kilocode/skills/git-workflow/SKILL.md @@ -27,6 +27,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/roo-code/.roo/rules/git-workflow.md b/roo-code/.roo/rules/git-workflow.md index 3be3074..9414911 100644 --- a/roo-code/.roo/rules/git-workflow.md +++ b/roo-code/.roo/rules/git-workflow.md @@ -23,6 +23,14 @@ gh issue list --search "keywords describing the task" ``` - **Issue exists:** note the issue number — every branch, commit, and PR must reference it. +- **Open PR already exists:** Before beginning any work, after confirming the issue number, check for open PRs that already address it: + ```bash + gh pr list --state open --search "# in:body,title" --json number,title,url + ``` + If one or more open PRs are returned: + - **Do not open a new PR** — a duplicate is already in flight. + - Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. + - Never open a second PR for the same issue unless the first is explicitly closed. - **No issue exists:** create one before starting. A good issue includes: - Clear problem description and context - Acceptance criteria (what "done" looks like) diff --git a/scripts/tests/test_dedup_rule.py b/scripts/tests/test_dedup_rule.py index 22862a3..94a2ad6 100644 --- a/scripts/tests/test_dedup_rule.py +++ b/scripts/tests/test_dedup_rule.py @@ -77,7 +77,7 @@ def test_dedup_rule_present(filepath: Path) -> None: """Every target file must contain the open-PR dedup rule.""" assert filepath.exists(), f"File not found: {filepath}" content = read_text(filepath) - assert "Open PR already exists" in content or "open PR" in content.lower(), ( + assert any(phrase in content for phrase in ("Open PR already exists", "Open PR check", "open-PR check", "No planner dispatch without open-PR check")), ( f"Dedup rule not found in {filepath.relative_to(REPO_ROOT)}\n" "Expected text signalling the open-PR check (e.g. 'Open PR already exists')" ) diff --git a/windsurf/.windsurf/rules/git-workflow.md b/windsurf/.windsurf/rules/git-workflow.md index afc4d5d..a94c3bc 100644 --- a/windsurf/.windsurf/rules/git-workflow.md +++ b/windsurf/.windsurf/rules/git-workflow.md @@ -19,6 +19,15 @@ gh issue list --search "keywords describing the task" ``` Issue exists → note the number; every branch, commit, and PR must reference it. + +Open PR check → Before beginning any work, check whether an open PR already addresses the issue: + +```bash +gh pr list --state open --search "# in:body,title" --json number,title,url +``` + +If one or more open PRs are returned: **Do not open a new PR** — a duplicate is already in flight. Reroute to plan-reviewer with the existing PR as input, OR halt and report the existing PR URL. Never open a second PR for the same issue unless the first is explicitly closed. + No issue → create one first. Include: problem description, acceptance criteria, affected files/components, security/privacy considerations, and constraints. ```bash From ad102d87a9d0ed59a74c71b24215f4b9d1274691 Mon Sep 17 00:00:00 2001 From: Original Gary <276612211+OpenGaryBot@users.noreply.github.com> Date: Fri, 1 May 2026 23:41:49 +1000 Subject: [PATCH 3/3] fix(#47): remove NAV-violating idiom from test comment The test file comment used a prohibited speciesist idiom as an example. Replaced with a neutral description to pass the no-animal-violence check. --- scripts/tests/test_dedup_rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/test_dedup_rule.py b/scripts/tests/test_dedup_rule.py index 94a2ad6..f409d64 100644 --- a/scripts/tests/test_dedup_rule.py +++ b/scripts/tests/test_dedup_rule.py @@ -214,7 +214,7 @@ def test_unicode_integrity_all_changed_files() -> None: # Test 7: no speciesist language introduced in changed files # # Behaviour: the dedup rule text must not introduce language that normalises -# animal violence (e.g. "kill two birds with one stone"). +# animal violence (e.g. idioms that normalize harm to animals). # Mutation kill: adding a prohibited idiom to any file fails this test. # # Implementation note: requires semgrep + the NAV config. If semgrep is not