Files
document-haness/scripts/tests/test_command_pedagogy_pipeline_contract.py
T

144 lines
6.4 KiB
Python

"""command-pedagogy가 실제 파이프라인 문서와 프롬프트에 연결되어 있는지 본다."""
from __future__ import annotations
import json
import os
import unittest
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
PIPELINE = os.path.join(ROOT, ".agents", "skills", "running-tech-log-pipeline")
def read(*parts: str) -> str:
with open(os.path.join(PIPELINE, *parts), encoding="utf-8") as fh:
return fh.read()
class CommandPedagogyPipelineContractTest(unittest.TestCase):
def test_pipeline_skill_routes_command_work_to_separate_agents(self):
text = read("SKILL.md")
for token in (
"check-command-pedagogy.py",
"command-pedagogy-planner",
"command-pedagogy-editor",
"command-pedagogy-reviewer",
"qualityReviews.commandPedagogy",
"qualityReviews.technicalEvidence",
):
self.assertIn(token, text)
self.assertIn("shell/CLI block이 없으면", text)
self.assertIn("finding이 없으면 planner/editor", text)
def test_stage_contract_freezes_bounded_command_repair(self):
text = read("references", "stage-contracts.md")
for token in (
"initialAnalysis",
"finalAnalysis",
"CommandPatchSet",
"apply-command-pedagogy-patch.py",
"majorFindings",
"command-pedagogy-reviewer",
"fact-reviewer",
):
self.assertIn(token, text)
self.assertIn("command block 밖의 산문", text)
def test_subagent_prompts_include_the_command_lane_and_final_reviews(self):
text = read("references", "subagent-prompts.md")
for call in (
'Agent(subagent_type="command-pedagogy-planner"',
'Agent(subagent_type="command-pedagogy-editor"',
'Agent(subagent_type="command-pedagogy-reviewer"',
'Agent(subagent_type="fact-reviewer"',
):
self.assertIn(call, text)
self.assertIn("CommandPatchSet", text)
self.assertIn("initial command analysis", text)
self.assertIn("final command analysis", text)
self.assertIn("validate-command-pedagogy-artifact.py", text)
self.assertIn("sha256", text.lower())
class FirstClassCommandContractTest(unittest.TestCase):
def test_command_plan_and_patch_set_have_repository_schemas(self):
schema_dir = os.path.join(PIPELINE, "schemas")
expectations = {
"command-plan.schema.json": {"section_id", "source_sha256", "mode", "command_groups"},
"command-patch-set.schema.json": {"source_sha256", "patches"},
}
for name, required in expectations.items():
path = os.path.join(schema_dir, name)
self.assertTrue(os.path.isfile(path), path)
with open(path, encoding="utf-8") as fh:
schema = json.load(fh)
self.assertEqual("https://json-schema.org/draft/2020-12/schema", schema["$schema"])
self.assertTrue(required.issubset(set(schema["required"])))
def test_claude_command_agents_are_thin_adapters_to_canonical_contracts(self):
pairs = {
"command-pedagogy-planner.md": "contracts/command-pedagogy-planner.md",
"command-pedagogy-editor.md": "contracts/command-pedagogy-editor.md",
"command-pedagogy-reviewer.md": "contracts/command-pedagogy-reviewer.md",
}
for adapter_name, canonical_rel in pairs.items():
canonical = os.path.join(PIPELINE, canonical_rel)
adapter = os.path.join(ROOT, ".claude", "agents", adapter_name)
self.assertTrue(os.path.isfile(canonical), canonical)
with open(adapter, encoding="utf-8") as fh:
adapter_text = fh.read()
self.assertIn(
f".agents/skills/running-tech-log-pipeline/{canonical_rel}",
adapter_text,
)
substantive = [line for line in adapter_text.splitlines() if line.strip()]
self.assertLessEqual(len(substantive), 14, adapter_name)
def test_command_authoring_policy_declares_modes_without_blanket_bans(self):
policy = os.path.join(PIPELINE, "policies", "command-authoring.yaml")
self.assertTrue(os.path.isfile(policy), policy)
with open(policy, encoding="utf-8") as fh:
content = fh.read()
for mode in ("tutorial", "operator", "diagnostic", "automation", "reference"):
self.assertIn(f" {mode}:", content)
self.assertIn("blanket_ban: false", content)
self.assertIn("validation_cleanup_same_chain", content)
def test_pipeline_structural_gate_requires_command_pedagogy_assets(self):
verifier = os.path.join(ROOT, "scripts", "verify-pipeline.py")
versions = os.path.join(ROOT, "scripts", "skill-versions.py")
with open(verifier, encoding="utf-8") as fh:
verifier_text = fh.read()
with open(versions, encoding="utf-8") as fh:
versions_text = fh.read()
required = (
".agents/skills/writing-practitioner-guides/references/command-pedagogy.md",
".agents/skills/running-tech-log-pipeline/policies/command-authoring.yaml",
".agents/skills/running-tech-log-pipeline/schemas/command-plan.schema.json",
".agents/skills/running-tech-log-pipeline/schemas/command-patch-set.schema.json",
".agents/skills/running-tech-log-pipeline/contracts/command-pedagogy-planner.md",
".agents/skills/running-tech-log-pipeline/contracts/command-pedagogy-editor.md",
".agents/skills/running-tech-log-pipeline/contracts/command-pedagogy-reviewer.md",
".claude/agents/command-pedagogy-planner.md",
".claude/agents/command-pedagogy-editor.md",
".claude/agents/command-pedagogy-reviewer.md",
"scripts/command_pedagogy.py",
"scripts/check-command-pedagogy.py",
"scripts/apply-command-pedagogy-patch.py",
"scripts/validate-command-pedagogy-artifact.py",
)
for rel in required:
self.assertIn(f'"{rel}"', verifier_text, rel)
for rel in (
"scripts/command_pedagogy.py",
"scripts/check-command-pedagogy.py",
"scripts/apply-command-pedagogy-patch.py",
"scripts/validate-command-pedagogy-artifact.py",
):
self.assertIn(f'"{rel}"', versions_text, rel)
if __name__ == "__main__":
unittest.main()