fix(garden): scope agent name normalization to the frontmatter block

Review feedback on PR #676. The substitution used a MULTILINE pattern with
count=1, which lands on the frontmatter name in every agent the repo has today
but would blank a body `name:` line in an agent whose frontmatter lacked one.

Normalization is now scoped to the opening frontmatter block, so a `name:` in
the body stays content and still counts toward a divergence. Three tests cover
differing body names, matching body names, and a file with no frontmatter.

No change to current output: still 11 divergent, 0 verbatim reported.
This commit is contained in:
Seth Hobson
2026-08-22 19:43:40 -04:00
parent 691f25f20a
commit 4798d40b49
2 changed files with 55 additions and 2 deletions
+18 -2
View File
@@ -55,8 +55,10 @@ COUNT_RE = re.compile(r"\b(\d+)\s+(plugins|agents|subagents|skills|commands)\b")
COUNT_NOUN_ALIASES = {"subagents": "agents"}
# An agent's frontmatter `name:` is plugin-namespaced, so two copies of the same
# agent can never hash alike. Normalize it away before comparing bodies.
# agent can never hash alike. Normalize it away before comparing bodies, scoped to
# the opening frontmatter block so a `name:` line in the body still counts as content.
AGENT_NAME_LINE_RE = re.compile(r"^name:.*$", re.MULTILINE)
AGENT_FRONTMATTER_RE = re.compile(r"\A(---\n)(.*?)(\n---\n)", re.DOTALL)
# ── Findings ─────────────────────────────────────────────────────────────────
@@ -392,6 +394,20 @@ def check_marketplace_consistency(report: Report) -> None:
)
def normalized_agent_text(text: str) -> str:
"""Blank the plugin-namespaced frontmatter `name:` so sibling copies compare equal.
Only the opening frontmatter block is touched. A `name:` line in the body is real
content and must still count toward a divergence.
"""
match = AGENT_FRONTMATTER_RE.match(text)
if not match:
return text
opener, frontmatter, closer = match.groups()
frontmatter = AGENT_NAME_LINE_RE.sub("name:", frontmatter, count=1)
return f"{opener}{frontmatter}{closer}{text[match.end() :]}"
def actual_counts() -> dict[str, int]:
"""Live component totals, counted the same way the adapters discover them.
@@ -451,7 +467,7 @@ def check_agent_divergence(report: Report) -> None:
continue
bodies: dict[str, list[Path]] = defaultdict(list)
for path in paths:
normalized = AGENT_NAME_LINE_RE.sub("name:", path.read_text(encoding="utf-8"), count=1)
normalized = normalized_agent_text(path.read_text(encoding="utf-8"))
bodies[hashlib.md5(normalized.encode("utf-8")).hexdigest()].append(path)
if len(bodies) > 1:
+37
View File
@@ -412,6 +412,43 @@ class TestAgentDivergence:
assert finding.severity == "warning"
assert "2 copies in 2 different versions" in finding.message
def test_body_name_lines_still_count_as_content(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
):
"""Only the frontmatter name is normalized; a `name:` in the body is real content."""
_patch_paths(monkeypatch, tmp_path)
_write_agent(tmp_path, "alpha", "reviewer.md", "Example config:\n\nname: alpha-thing\n")
_write_agent(tmp_path, "beta", "reviewer.md", "Example config:\n\nname: beta-thing\n")
report = Report()
check_agent_divergence(report)
assert [f.kind for f in report.findings] == ["AGENT_BODY_DIVERGENT"]
def test_body_name_lines_matching_stay_verbatim(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
):
"""Same body `name:` plus differing frontmatter names is still a verbatim copy."""
_patch_paths(monkeypatch, tmp_path)
_write_agent(tmp_path, "alpha", "reviewer.md", "Example config:\n\nname: shared\n")
_write_agent(tmp_path, "beta", "reviewer.md", "Example config:\n\nname: shared\n")
report = Report()
check_agent_divergence(report)
assert report.findings == []
def test_agent_without_frontmatter_does_not_crash(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
):
_patch_paths(monkeypatch, tmp_path)
for plugin in ("alpha", "beta"):
agents_dir = tmp_path / "plugins" / plugin / "agents"
agents_dir.mkdir(parents=True, exist_ok=True)
(agents_dir / "bare.md").write_text("No frontmatter here.\n")
report = Report()
check_agent_divergence(report)
assert report.findings == []
def test_groups_variants_in_message(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
"""Three copies sharing two bodies report as 3 copies / 2 versions."""
_patch_paths(monkeypatch, tmp_path)