zizi 952485a506 框架: 前期创作流程代码——细纲统一合同+字段覆盖门禁+文风/范式注入+取数端统一
修五个硬伤,让"前期准备"从文档纪律变成机械门禁,并补齐写作链上游注入:
- 细纲合同合一:新建 meta/schemas/fine_outline.yaml 作唯一字段权威(必填9+推荐7),
  统一此前 planning 产出形与 writer 装配消费形两套不相交字段;fine-outline 技能对齐。
- 落库字段覆盖门禁:persist_planning 按 schema 校验必填字段,缺必填失败关闭,
  「字段存疑」逃生口;只对声明「字段覆盖门禁:强制」的型生效(fine_outline 已强制)。
- 文风真注入:WriterContext 增可选 styleConstraints(空则省键、上下文逐字节不变),
  装配投影给 writer,不再写死为空。
- 范式规划期绑定:read-context load_confirmed_pattern_bindings 只读已确认 assembly 绑定
  (实验仓承载,确认即绑定,不改主仓表);生产脚本注入已绑定范式。
- 取数端统一:read-context 三个一等取数端(细纲/范式/文风),生产编排 step2 接线,
  已确认细纲不再人肉读库传参。
- harness:AGENTS.md 第9节新增「提交前必须独立子代理形而上四维审查」硬规则。
(writer_contract/retrieve 含上一会话 asOf=0 开篇冻结线改动,同属创作链修复,随本笔提交。)

测试:9 套全绿(合同6/门禁8/装配17/writer_contract21/检索11/统一3/细纲读取4/范式读取5/文风读取6)。
2026-08-02 02:17:14 +08:00

79 lines
2.9 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
ROOT = Path(__file__).resolve().parents[4]
SKILL = (ROOT / ".claude/skills/fine-outline/SKILL.md").read_text(encoding="utf-8")
PLANNER = (ROOT / ".claude/agents/planner.md").read_text(encoding="utf-8")
CHAINS = (ROOT / "meta/chains/README.md").read_text(encoding="utf-8")
SCHEMA = (ROOT / "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()