Files
aiturk-hermes-ide/tests/skills/test_sdlc_review_skill.py
T

96 lines
2.9 KiB
Python

"""Contract tests for the bundled SDLC review skill."""
from __future__ import annotations
import re
from pathlib import Path
import pytest
SKILL_MD = (
Path(__file__).resolve().parents[2]
/ "skills"
/ "devops"
/ "sdlc-review"
/ "SKILL.md"
)
REQUIRED_SECTIONS = [
"## When to Use",
"## Prerequisites",
"## How to Run",
"## Quick Reference",
"## Review Lenses",
"## Procedure",
"## Pitfalls",
"## Verification",
]
REVIEW_ACTIONS = {
"kanban_show",
"kanban_comment",
"kanban_complete",
"kanban_request_changes",
"kanban_block",
}
@pytest.fixture(scope="module")
def skill_text() -> str:
return SKILL_MD.read_text(encoding="utf-8")
def _frontmatter_value(text: str, key: str) -> str:
match = re.search(rf"^{re.escape(key)}:\s*(.+)$", text, re.MULTILINE)
assert match, f"missing frontmatter field: {key}"
return match.group(1).strip()
def test_frontmatter_meets_hardline_standard(skill_text: str) -> None:
assert skill_text.startswith("---\n")
assert _frontmatter_value(skill_text, "name") == "sdlc-review"
description = _frontmatter_value(skill_text, "description")
assert len(description) <= 60
assert description.endswith(".")
for field in ("version", "author", "license", "platforms"):
assert _frontmatter_value(skill_text, field)
assert not _frontmatter_value(skill_text, "author").startswith("Hermes Agent")
def test_body_uses_required_modern_section_order(skill_text: str) -> None:
assert "# SDLC Review Skill" in skill_text
positions = [skill_text.index(section) for section in REQUIRED_SECTIONS]
assert positions == sorted(positions)
@pytest.mark.parametrize("tool_name", sorted(REVIEW_ACTIONS))
def test_skill_documents_native_review_actions(
skill_text: str,
tool_name: str,
) -> None:
assert f"`{tool_name}`" in skill_text
def test_verdicts_route_through_distinct_terminal_actions(skill_text: str) -> None:
quick_reference = skill_text.split("## Quick Reference", 1)[1].split(
"## Review Lenses", 1
)[0]
assert "Approve" in quick_reference and "`kanban_complete`" in quick_reference
assert "Request changes" in quick_reference
assert "`kanban_request_changes`" in quick_reference
assert "Escalate" in quick_reference and "`kanban_block`" in quick_reference
def test_review_lenses_vary_per_round(skill_text: str) -> None:
lenses = skill_text.split("## Review Lenses", 1)[1].split("## Procedure", 1)[0]
# Round derivation must key off history the reviewer actually sees.
assert "`changes_requested`" in lenses
assert "Prior attempts on this task" in lenses
# One distinct lens per round.
for lens in ("Artifact", "Execution", "Contract"):
assert lens in lenses
# Execution lens must direct empirical verification via the terminal.
assert "`terminal`" in lenses
# Fan-out note: parallel reviewers get different briefs.
assert "`delegate_task`" in lenses