Group playbook.toml-driven behavior tests under a single config-actions file and split parser/template contract coverage into focused files. Remove obsolete PowerShell audit scripts and tracked validation reports; write template validation reports under reports/templates.
203 lines
10 KiB
Python
203 lines
10 KiB
Python
import unittest
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
class TemplateContractsTests(unittest.TestCase):
|
|
def test_project_templates_drop_legacy_language_placeholders(self):
|
|
example_text = (ROOT / "playbook.toml.example").read_text(encoding="utf-8")
|
|
self.assertNotIn("main_language", example_text)
|
|
|
|
templates_readme = (ROOT / "templates" / "README.md").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
self.assertNotIn("{{MAIN_LANGUAGE}}", templates_readme)
|
|
self.assertNotIn("{{LANGUAGE_1}}", templates_readme)
|
|
self.assertNotIn("docs/workflows/", templates_readme)
|
|
self.assertNotIn("templates/workflows/", templates_readme)
|
|
self.assertIn("docs/superpowers/", templates_readme)
|
|
self.assertIn("docs/prompts/README.md", templates_readme)
|
|
self.assertIn("完整主链只在 `AGENT_RULES.template.md` 定义", templates_readme)
|
|
|
|
agents_template = (ROOT / "templates" / "AGENTS.template.md").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
self.assertNotIn("{{MAIN_LANGUAGE}}", agents_template)
|
|
self.assertIn("AGENT_RULES.md", agents_template)
|
|
self.assertIn("docs/prompts/README.md", agents_template)
|
|
|
|
tech_context_template = (
|
|
ROOT / "templates" / "memory-bank" / "tech-context.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertNotIn("{{MAIN_LANGUAGE}}", tech_context_template)
|
|
self.assertNotIn("{{LANGUAGE_1}}", tech_context_template)
|
|
self.assertNotIn("**主要语言**", tech_context_template)
|
|
self.assertIn("## 不可假设项", tech_context_template)
|
|
|
|
project_brief_template = (
|
|
ROOT / "templates" / "memory-bank" / "project-brief.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("## 成功定义", project_brief_template)
|
|
|
|
def test_memory_bank_templates_capture_short_lived_context_contracts(self):
|
|
progress_template = (
|
|
ROOT / "templates" / "memory-bank" / "progress.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("短期状态快照,不是 changelog", progress_template)
|
|
self.assertIn("`Recent Changes` 只保留最近 3-5 条", progress_template)
|
|
self.assertIn("整理/替换旧摘要,不做无限追加", progress_template)
|
|
|
|
active_context_template = (
|
|
ROOT / "templates" / "memory-bank" / "active-context.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("短期上下文快照,不是长期日志", active_context_template)
|
|
self.assertIn("`Recent Changes` 只保留最近 3-5 条", active_context_template)
|
|
self.assertIn(
|
|
"`Touched Files` 只保留当前 Plan / 下一轮仍相关的文件",
|
|
active_context_template,
|
|
)
|
|
self.assertIn("整理/替换旧上下文,不做无限追加", active_context_template)
|
|
|
|
def test_prompt_templates_point_to_current_superpowers_flow(self):
|
|
update_memory_template = (
|
|
ROOT / "templates" / "prompts" / "coding" / "update-memory.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertNotIn("workflow-state", update_memory_template)
|
|
self.assertIn("plan-status", update_memory_template)
|
|
self.assertIn("## Updated Files", update_memory_template)
|
|
self.assertIn("## New Context", update_memory_template)
|
|
self.assertIn("## Outstanding Risks", update_memory_template)
|
|
self.assertIn("AGENT_RULES.local.md", update_memory_template)
|
|
self.assertIn("短期状态快照", update_memory_template)
|
|
self.assertIn(
|
|
"不要把 `Recent Changes` 当作无限追加日志", update_memory_template
|
|
)
|
|
self.assertIn("短期上下文快照", update_memory_template)
|
|
self.assertIn(
|
|
"`Touched Files` 只保留当前 Plan / 下一轮仍相关的文件",
|
|
update_memory_template,
|
|
)
|
|
|
|
close_task_template = (
|
|
ROOT / "templates" / "prompts" / "coding" / "close-task.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("main_loop.py finish", close_task_template)
|
|
self.assertIn("如本轮来自 `main_loop.py claim`", close_task_template)
|
|
self.assertNotIn("workflow-state", close_task_template)
|
|
self.assertIn("未归档不得声明 Plan 完成", close_task_template)
|
|
self.assertIn("按项目归档机制只归档", close_task_template)
|
|
self.assertIn("状态已写回,交付未完成", close_task_template)
|
|
self.assertIn("## Completed", close_task_template)
|
|
self.assertIn("## Not Completed", close_task_template)
|
|
self.assertIn("## Verification", close_task_template)
|
|
self.assertIn("## Risks", close_task_template)
|
|
self.assertIn("## Next Steps", close_task_template)
|
|
|
|
verify_change_template = (
|
|
ROOT / "templates" / "prompts" / "coding" / "verify-change.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("如本轮来自 `main_loop.py claim`", verify_change_template)
|
|
self.assertNotIn("workflow-state", verify_change_template)
|
|
self.assertIn("plan-status", verify_change_template)
|
|
self.assertIn("验证通过不等于 Plan 完成", verify_change_template)
|
|
self.assertIn(
|
|
"当前 Plan 相关差异未归档/提交时,不得声明 Plan 完成",
|
|
verify_change_template,
|
|
)
|
|
self.assertIn("## Validated", verify_change_template)
|
|
self.assertIn("## Evidence", verify_change_template)
|
|
self.assertIn("## Not Validated", verify_change_template)
|
|
self.assertIn("## Risks", verify_change_template)
|
|
|
|
clarify_template = (
|
|
ROOT / "templates" / "prompts" / "coding" / "clarify.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertNotIn("Vibe-coding", clarify_template)
|
|
self.assertIn("## Current Understanding", clarify_template)
|
|
self.assertIn("## Open Question", clarify_template)
|
|
self.assertIn("## Recommended Default", clarify_template)
|
|
|
|
code_review_template = (
|
|
ROOT / "templates" / "prompts" / "coding" / "code-review.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("## Findings", code_review_template)
|
|
self.assertIn("## Open Questions", code_review_template)
|
|
self.assertIn("## Residual Risk", code_review_template)
|
|
|
|
prompts_readme = (ROOT / "templates" / "prompts" / "README.md").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
self.assertIn("AGENT_RULES.md", prompts_readme)
|
|
self.assertIn("docs/superpowers/", prompts_readme)
|
|
self.assertIn("不是流程权威", prompts_readme)
|
|
self.assertNotIn("playbook.py -record-spec", prompts_readme)
|
|
self.assertNotIn("playbook.py -record-plan", prompts_readme)
|
|
self.assertNotIn("using-superpowers", prompts_readme)
|
|
self.assertNotIn("main_loop.py claim", prompts_readme)
|
|
self.assertNotIn("docs/workflows/", prompts_readme)
|
|
self.assertIn("设计与计划产物", prompts_readme)
|
|
|
|
agent_behavior_template = (
|
|
ROOT / "templates" / "prompts" / "system" / "agent-behavior.template.md"
|
|
).read_text(encoding="utf-8")
|
|
self.assertIn("AGENT_RULES.md", agent_behavior_template)
|
|
self.assertIn("AGENT_RULES.local.md", agent_behavior_template)
|
|
self.assertIn("docs/superpowers/specs/", agent_behavior_template)
|
|
self.assertIn("docs/superpowers/plans/", agent_behavior_template)
|
|
self.assertNotIn("using-superpowers", agent_behavior_template)
|
|
self.assertNotIn("main_loop.py claim", agent_behavior_template)
|
|
self.assertNotIn("playbook.py -record-spec", agent_behavior_template)
|
|
self.assertNotIn("playbook.py -record-plan", agent_behavior_template)
|
|
self.assertIn(
|
|
"项目上下文与执行状态写入 `memory-bank/`", agent_behavior_template
|
|
)
|
|
|
|
def test_agent_rules_template_defines_plan_and_archival_contracts(self):
|
|
rules_template = (ROOT / "templates" / "AGENT_RULES.template.md").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
self.assertIn("框架流程约束基线", rules_template)
|
|
self.assertIn("{{PLAYBOOK_ROOT}}", rules_template)
|
|
self.assertIn("Playbook 模板/供应商目录", rules_template)
|
|
self.assertIn("唯一设计与计划产物中心", rules_template)
|
|
self.assertIn("memory-bank/progress.md", rules_template)
|
|
self.assertIn("优先恢复 `in-progress`", rules_template)
|
|
self.assertIn("选择第一个可执行 Plan", rules_template)
|
|
self.assertIn(
|
|
"`main_loop.py finish -status done` 只负责写回机器状态",
|
|
rules_template,
|
|
)
|
|
self.assertIn(
|
|
"Plan `done` 后必须完成当前 Plan 变更的归档/提交", rules_template
|
|
)
|
|
self.assertIn(
|
|
"spec/plan 产出阶段不单独提交或归档", rules_template
|
|
)
|
|
self.assertIn(
|
|
"如外部 skill", rules_template
|
|
)
|
|
self.assertIn("Plan 范围是归档/提交边界", rules_template)
|
|
self.assertIn(
|
|
"不自动提交或归档",
|
|
rules_template,
|
|
)
|
|
self.assertIn("当前 Plan 文件", rules_template)
|
|
self.assertIn("`memory-bank/progress.md`", rules_template)
|
|
self.assertIn("必要 memory 更新", rules_template)
|
|
self.assertIn("允许其未归档共存", rules_template)
|
|
self.assertIn("当前 Plan 无遗留差异", rules_template)
|
|
self.assertIn("状态已写回,交付未完成", rules_template)
|
|
self.assertNotIn("如项目使用 Git", rules_template)
|
|
self.assertNotIn("Git 提交", rules_template)
|
|
self.assertNotIn("git status", rules_template)
|
|
self.assertNotIn("git commit", rules_template)
|
|
self.assertNotIn("git worktree", rules_template)
|
|
self.assertNotIn(".gitattributes", rules_template)
|
|
self.assertIn("`progress.md` 上半部分是短期状态快照", rules_template)
|
|
self.assertIn("`active-context.md` 是短期上下文快照", rules_template)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|