muse-agent-example/docs/write-chapter/step2_setup_chapter3.py
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

111 lines
6.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
"""真写一章 · 阶段二前置:建第 3 章 + 章级细纲(规划落库)。
镜像 step2_setup_chapter2.py 的建章 + persist_planning 模式。第 3 章细纲接第 2 章
结尾硬钩子(「茧」自己撕开舱门出击、裴朔下达出击授权、它要吃掉更强的核心),按
总纲「机甲养成升级线 + 污染不可逆」展开:首次实战、吞食更强异种核心完成第一次
升级、链接加深、污染同步恶化、脑内声音与林深自我边界开始模糊。
细纲 payload 形状与第 2 章一致(合同形状):
- 合同四件套(sourceRef/hardConstraints/adjustableBeats/declaredNewFacts)满足
assemble 的 _outline_contract 与 WriterContext 严格校验;declaredNewFacts 是
{factId,text,sourceRef} 对象。
- chapterGoal/keyEvents/mustAppearEntities/chapterEndHook 是规划侧字段,assemble 会裁剪,
留给人工审查与机械门的锚点映射。
- entities 供 build_retrieval_plan 生成检索查询(新书无卡,检索会诚实返空)。
"""
import sys
from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
DB_SCRIPTS = SCRIPT_DIR.parents[1] / ".claude" / "skills" / "db" / "scripts"
PLANNING_SCRIPTS = SCRIPT_DIR.parents[1] / ".claude" / "skills" / "planning" / "scripts"
for p in (str(DB_SCRIPTS), str(PLANNING_SCRIPTS)):
if p not in sys.path:
sys.path.insert(0, p)
from db import connect # noqa: E402
from persist_planning import write_section, confirm_section # noqa: E402
WORK_ID = 12
CHAPTER3_TITLE = "进食"
FINE_OUTLINE_PAYLOAD = {
"targetChapter": 3,
"targetChars": 4000,
"chapterGoal": ("「茧」撕开舱门出击后的首次实战。林深驾驶茧拦截一头更强的异种,"
"在近乎被压制的搏杀中,茧吞食了它的异种核心,完成第一次升级;"
"链接随之加深,林深获得跨层感知(能直接'读'深渊的波纹),"
"代价是污染不可逆地恶化——左眼黑纹继续扩散,脑内的声音越来越像"
"他自己,人与机甲、与异种之间的边界开始模糊。"),
"hardConstraints": [
"衔接第2章结尾:茧未经弹射自行撕开实验舰外舱门出击,裴朔已下出击授权,机甲饥饿直接、没有谎言,目标是吃掉一个更强的核心。",
"首次实战对象是一个比第1章杂兵更强的异种单位;搏杀有真实的压制与险情,不是碾压。",
"茧通过吞食更强异种核心完成第一次升级,链接加深,林深获得新的感知或力量(升级线落地,不只是变强数字)。",
"污染随这次吞食不可逆加深:左眼黑纹扩散,脑内声音与林深的自我边界模糊(他开始分不清哪个念头是自己的)。",
"舰队在后方通过链路监控这次出击,裴朔/何岚至少一方观察到茧的异常成长与林深的污染读数。",
"章末钩子:升级后的茧/林深引来了深渊更深处的注意,或核心指向下一个更强的猎物——饥饿没有止境。",
],
"keyEvents": [
{"id": "event-1", "order": 1, "event": "茧冲入战场锁定更强异种,交手即被压制",
"participants": ["林深", "生物机甲茧"], "trigger": "茧循饥饿扑向更强核心",
"resultDirection": "暴露升级前的不足,陷入险境"},
{"id": "event-2", "order": 2, "event": "链接加深,林深首次主动读到深渊波纹找到破局点",
"participants": ["林深", "生物机甲茧"], "trigger": "搏杀逼迫人机链接深入",
"resultDirection": "扭转战局,污染随之加深"},
{"id": "event-3", "order": 3, "event": "茧吞噬异种核心完成第一次升级",
"participants": ["生物机甲茧"], "trigger": "异种被击败、核心暴露",
"resultDirection": "机体与感知同时蜕变,升级线落地"},
{"id": "event-4", "order": 4, "event": "污染恶化,脑内声音与林深边界模糊",
"participants": ["林深"], "trigger": "吞食更强核心使链接与污染同步加深",
"resultDirection": "林深分不清是谁在渴望,不可逆"},
{"id": "event-5", "order": 5, "event": "舰队侧观察到异常成长与污染读数",
"participants": ["裴朔"], "trigger": "链路监控回传升级与污染数据",
"resultDirection": "埋下后续裁决伏笔"},
],
"adjustableBeats": [
"搏杀的具体战术与险情设计可调整(须有真实压制,不许写成碾压)。",
"升级获得的具体能力可调整(须是'感知/链接'向,服务于深渊设定,不凭空给战力)。",
"舰队侧观察的视角(裴朔或何岚)与比重可调整。",
],
"declaredNewFacts": [
{"factId": "fact-ch3-1",
"text": "茧吞食更强异种核心即可升级:机体蜕变、链接加深,林深获得跨层感知,能直接读取深渊波纹。",
"sourceRef": {"sourceId": "outline:volume_1", "sourceVersion": "v1"}},
{"factId": "fact-ch3-2",
"text": "污染随每次吞食不可逆加深:左眼黑纹扩散,脑内声音与林深自我边界模糊,人与机甲、异种的界限开始溶解。",
"sourceRef": {"sourceId": "outline:volume_1", "sourceVersion": "v1"}},
],
"mustAppearEntities": ["林深", "生物机甲茧", "裴朔"],
"chapterEndHook": ("升级完成的茧在深空中安静下来,饥饿却没有消失。林深'听'见深渊"
"更深处有什么东西回应了这次的进食——更大的核心,更深的召唤。"
"它要的从来不止这一顿。"),
"sourceRef": {"sourceId": "outline:volume_1", "sourceVersion": "v1"},
"entities": [
{"id": "entity-ch3-char-linshen", "type": "character", "name": "林深"},
{"id": "entity-ch3-char-peishuo", "type": "character", "name": "裴朔"},
{"id": "entity-ch3-item-cocoon", "type": "item", "name": "生物机甲茧"},
{"id": "entity-ch3-loc-deepspace", "type": "location", "name": "深空战场"},
],
}
def main():
with connect() as conn:
chapter_id = conn.execute(
"INSERT INTO muse_content_chapter(work_id, title, order_no, status, revision, "
"creator, updater) VALUES (%s,%s,3,'draft',1,'setup','setup') RETURNING id",
(WORK_ID, CHAPTER3_TITLE)).fetchone()[0]
print(f"建第 3 章: id={chapter_id} 《{CHAPTER3_TITLE}》")
conn.commit()
fine = write_section(WORK_ID, section_type="fine_outline", schema_type="fine_outline",
target_chapter=3, payload=FINE_OUTLINE_PAYLOAD)
confirm_section(fine["id"])
print(f"第3章细纲: section id={fine['id']} → confirmed")
print(f"\nCHAPTER3_ID={chapter_id}\nFINE_SECTION_ID={fine['id']}")
if __name__ == "__main__":
main()