83 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""细纲功能合同的离线回归测试,不启动模型、不访问作品数据。
字段权威 = meta/schemas/fine_outline.yaml;本测试同时校验技能文档(产出侧)与
该 schema(字段权威)声明的必填/推荐字段一致,防止两者再次漂移。
"""
from pathlib import Path
import unittest
PROJECT_ROOT = Path(__file__).resolve().parents[3]
SKILL = (
PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "chapter" / "规划下一章" / "SKILL.md"
).read_text(encoding="utf-8")
PLANNER = (PROJECT_ROOT / ".agent" / "agents" / "planner.md").read_text(encoding="utf-8")
CHAINS = (PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "chains" / "README.md").read_text(encoding="utf-8")
SCHEMA = (
PROJECT_ROOT / "muse" / "content" / "meta" / "schemas" / "fine_outline.yaml"
).read_text(encoding="utf-8")
# 与 meta/schemas/fine_outline.yaml 的必填/推荐集保持一致。
REQUIRED_FIELDS = (
"targetChapter",
"sourceRef",
"chapterGoal",
"hardConstraints",
"keyEvents",
"adjustableBeats",
"declaredNewFacts",
"mustAppearEntities",
"chapterEndHook",
)
RECOMMENDED_FIELDS = (
"foreshadowing",
"entities",
"stateChanges",
"unknowns",
"assumptions",
"sourceRefs",
"targetChars",
)
class FineOutlineContractTest(unittest.TestCase):
def test_contract_is_bound_to_existing_planner_slot(self):
self.assertIn("scenario: fine_outline", SKILL)
self.assertIn("fine_outline", PLANNER)
self.assertIn("fine_outline", CHAINS)
self.assertIn("规划→planner", CHAINS)
def test_skill_cites_schema_as_field_authority(self):
# 技能文档必须把字段权威指向 schema,不再自持一套字段集。
self.assertIn("meta/schemas/fine_outline.yaml", SKILL)
self.assertIn("字段权威", SCHEMA)
def test_required_fields_present_in_skill_and_schema(self):
for field in REQUIRED_FIELDS:
self.assertIn(field, SKILL, f"技能文档缺必填字段 {field}")
self.assertIn(field, SCHEMA, f"schema 缺必填字段 {field}")
# hook 已统一为 chapterEndHook,不应再以裸 hook 作字段名出现于必填纪律。
self.assertIn("chapterEndHook", SKILL)
def test_recommended_fields_present_in_skill_and_schema(self):
for field in RECOMMENDED_FIELDS:
self.assertIn(field, SKILL, f"技能文档缺推荐字段 {field}")
self.assertIn(field, SCHEMA, f"schema 缺推荐字段 {field}")
def test_shadow_boundary_and_red_lines_are_explicit(self):
self.assertIn("不得输出正文", SKILL)
self.assertIn("Shadow", SKILL)
self.assertIn("目标章细纲作为生成输入", SKILL)
def test_freeze_and_two_line_retrieval_rules_are_explicit(self):
self.assertIn("<= as_of", SKILL)
self.assertIn("卡是检索索引和事实补充", SKILL)
self.assertIn("目标章正文", SKILL)
self.assertIn("unknowns", SKILL)
if __name__ == "__main__":
unittest.main()