diff --git a/docs/2026-09-01-创作链路合同校准提交前四维审查报告.md b/docs/2026-09-01-创作链路合同校准提交前四维审查报告.md new file mode 100644 index 0000000..fb84f67 --- /dev/null +++ b/docs/2026-09-01-创作链路合同校准提交前四维审查报告.md @@ -0,0 +1,44 @@ +# 2026-09-01 创作链路合同校准提交前四维审查报告 + +verdict: PASS + +## 审查范围 + +- `muse/sot/创作周期与Skill导读.md` +- `muse/sot/domains/05-创作流程领域.md` +- `muse/lifecycle/flow/chains/README.md` +- `muse/content/work/skills/generate/写下一章/SKILL.md` +- `muse/lifecycle/context/skills/准备任务上下文/SKILL.md` +- `muse/技能目录.md` +- 实现补充核对:`muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py` +- 回显补充核对:`muse/authority/studio/read/server.py` +- 验证补充核对:`tests/skills/写下一章/test_gate_anchor_projection.py`、`muse/authority/studio/read/test_server_display.py` + +排除项:`docs/实现回顾/技能身份中文化迁移实现回顾.md`、`muse/platform/llm/src/muse_llm.py` + +## 逻辑完整性 + +- PASS:阶段 0 现在明确区分“前期多案候选”与“正式 `setting` Shadow”,退出条件不再自相矛盾;SoT 与场景 Skill 已对齐。[muse/sot/domains/05-创作流程领域.md:19](../muse/sot/domains/05-创作流程领域.md#L19) [muse/sot/创作周期与Skill导读.md:121](../muse/sot/创作周期与Skill导读.md#L121) +- PASS:节点 W 现在明确是“探索 → 回放 → 无工具生成”,不再把“来源优先级固定”误写成“全量预拼后直接喂给生成阶段”。[muse/sot/domains/05-创作流程领域.md:129](../muse/sot/domains/05-创作流程领域.md#L129) [muse/sot/domains/05-创作流程领域.md:173](../muse/sot/domains/05-创作流程领域.md#L173) [muse/content/work/skills/generate/写下一章/SKILL.md:13](../muse/content/work/skills/generate/写下一章/SKILL.md#L13) +- PASS:生产入口已把作品维度参数化到 CLI、运行编号、授权快照和门锚读取,不再只在入口层硬编码作品 12。[muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py:16](../muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py#L16) [muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py:259](../muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py#L259) [muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py:304](../muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py#L304) + +## 一致性 + +- PASS:`写下一章` 的目录描述、Skill 合同、链路登记和导读都统一为“两阶段写手”,不再同时出现“不得自行检索”和“探索阶段允许白名单只读工具”这组冲突表述。[muse/技能目录.md:63](../muse/技能目录.md#L63) [muse/content/work/skills/generate/写下一章/SKILL.md:1](../muse/content/work/skills/generate/写下一章/SKILL.md#L1) [muse/lifecycle/flow/chains/README.md:19](../muse/lifecycle/flow/chains/README.md#L19) +- PASS:raw 留痕口径统一为“PostgreSQL raw 表是正式留痕,仓外 raw vault 只是临时暂存或可选备份”,与数据权威域一致。[muse/lifecycle/context/skills/准备任务上下文/SKILL.md:63](../muse/lifecycle/context/skills/准备任务上下文/SKILL.md#L63) [muse/sot/domains/08-数据权威与可视化领域.md:70](../muse/sot/domains/08-数据权威与可视化领域.md#L70) +- PASS:只读看板的“改:”命令现在跟随当前运行/候选的作品与章节,不再把用户带回作品 12 第 3 章的旧入口口径。[muse/authority/studio/read/server.py:2489](../muse/authority/studio/read/server.py#L2489) [muse/authority/studio/read/test_server_display.py:94](../muse/authority/studio/read/test_server_display.py#L94) + +## 合理性 + +- PASS:`DEFAULT_WORK_ID=12` 保留了既有样本兼容性,但新增 `--work-id` 和 `resolve_gate_requirements()`,避免破坏现有运行习惯,同时把作品切换收敛到显式参数。[muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py:93](../muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py#L93) [muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py:259](../muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py#L259) +- PASS:门锚仍按作品+章节显式登记,未把“样本常量”直接伪装成“所有作品通用规则”;文档把这一点保留为真实待建项,避免假完成。[muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py:113](../muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py#L113) [muse/sot/domains/05-创作流程领域.md:271](../muse/sot/domains/05-创作流程领域.md#L271) [muse/sot/创作周期与Skill导读.md:662](../muse/sot/创作周期与Skill导读.md#L662) + +## 可行性 + +- PASS:机械验证已覆盖改动落点。`skill_harness --strict` 通过;相关单测 40 条通过;架构测试 `test_author_instructions.py` 5 条、`test_markdown_links.py` 2 条、`test_skills_index.py` 3 条通过;`skills_index.py --check` 通过;`git diff --check` 通过。 +- PASS:新增测试直接覆盖了作品级门锚解析与看板重产命令回填,说明本次修复不是只改文档。[tests/skills/写下一章/test_gate_anchor_projection.py:38](../tests/skills/写下一章/test_gate_anchor_projection.py#L38) [muse/authority/studio/read/test_server_display.py:94](../muse/authority/studio/read/test_server_display.py#L94) + +## 残余待建 + +- 门锚还没有从细纲或正式规划中自动派生,仍需按作品+章节登记;未登记即失败关闭。这是保留的真实边界,不构成阻断本次提交。 +- 章后抽取异步执行、方法 Skill 自动只读检查、结构化 `style` 八字段抽取仍待建,文档已明确保留。 diff --git a/docs/目录.md b/docs/目录.md index a92f640..89eb9f2 100644 --- a/docs/目录.md +++ b/docs/目录.md @@ -11,6 +11,7 @@ | 模块概要 | 暂无 | 某模块一页纸:干什么、入口在哪 | 第一次接触某模块、给别人指路时 | 模块对外形状变了 | | 实现回顾 | 实现回顾/目录.md | 功能实际怎么落地、和设计有何出入 | 后续改同一功能、交接、对照设计时 | 功能合并后留回顾 | | 缺陷回顾 | 暂无 | bug 根因、修法、如何防再发 | 同类故障、改相关代码前 | 非平凡 bug 修完留根因时 | +| 2026-09-01 创作链路合同校准提交前四维审查报告 | 2026-09-01-创作链路合同校准提交前四维审查报告.md | 本次提交前对创作链 SoT/Skill/实现校准差异的四维审查结论与验证证据 | 提交前确认本轮变更是否可交付时 | 只对应本次合同校准提交,不替代长期 SoT | | acceptance | acceptance/ | | | | | design | design/ | | | | | plans | plans/ | | | | diff --git a/muse/authority/studio/read/server.py b/muse/authority/studio/read/server.py index 2c6724c..d79bc16 100644 --- a/muse/authority/studio/read/server.py +++ b/muse/authority/studio/read/server.py @@ -2486,6 +2486,18 @@ def _run_input_summary_panel(run_id: str) -> str: def _run_decision_menu_panel(run_id: str, candidates: list, terminal_state, pipeline: dict | None) -> str: """决策菜单:有候选按候选态;无候选(失败关闭未落行)只给「改」重产命令。""" + def _rewrite_targets(): + if candidates: + latest = candidates[-1] + work_id = latest.get("work_id") or latest.get("workId") + target_chapter = latest.get("target_chapter") or latest.get("targetChapter") + if work_id is not None and target_chapter is not None: + return int(work_id), int(target_chapter) + matched = re.search(r"run-prod-work(\d+)-ch(\d+)-", run_id) + if matched: + return int(matched.group(1)), int(matched.group(2)) + return 12, 3 + pipe = pipeline or {} fail = pipe.get("failureCode") or "" gaps = [] @@ -2501,8 +2513,10 @@ def _run_decision_menu_panel(run_id: str, candidates: list, terminal_state, pipe gap_hints.append(str(g["query"])[:80]) # 预填改指令:绕开不可证缺口(阶段 0.1 选 A 时用) avoid = ";".join(f"避开「{h}」" for h in gap_hints[:2]) if gap_hints else "按语义/诊断理由修改" + rewrite_work_id, rewrite_target = _rewrite_targets() rewrite_cmd = ( - f".venv/bin/python muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py 3 " + f".venv/bin/python muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py {rewrite_target} " + f"--work-id {rewrite_work_id} " f"--provider

--model " f"--instruction \"改:{avoid}。禁止细纲原句抄进正文;门符号只在舰队医疗舱语境。\"" ) diff --git a/muse/authority/studio/read/test_server_display.py b/muse/authority/studio/read/test_server_display.py index af432b6..74c1fc8 100644 --- a/muse/authority/studio/read/test_server_display.py +++ b/muse/authority/studio/read/test_server_display.py @@ -91,6 +91,16 @@ class DashboardDisplayTest(unittest.TestCase): self.assertIn("写手", text) self.assertIn("第2章《称量》", text) + def test决策菜单重产命令跟随当前运行作品和章节(self): + html = server._run_decision_menu_panel( + "run-prod-work27-ch8-deadbeef", + [{"id": 91, "state": "passed", "work_id": 27, "target_chapter": 8}], + "completed", + None, + ) + self.assertIn("--work-id 27", html) + self.assertIn("produce_next_chapter.py 8", html) + def test原始_JSON_错误信息可读(self): text = server._content_text('{"failureType":"InvalidTextRepresentation"}') self.assertIn('"failureType": "InvalidTextRepresentation"', text) diff --git a/muse/content/work/skills/generate/写下一章/SKILL.md b/muse/content/work/skills/generate/写下一章/SKILL.md index 80c46f2..58e0b7b 100644 --- a/muse/content/work/skills/generate/写下一章/SKILL.md +++ b/muse/content/work/skills/generate/写下一章/SKILL.md @@ -1,6 +1,6 @@ --- name: 写下一章 -description: 按已确认细纲、冻结事实和动态篇幅合同生成下一整章候选。作品需要续写下一章且输入合同完整时使用;不自行检索、不改规划、不把候选直接写入 Canonical。 +description: 通过“白名单探索→确定性回放→无工具生成”两阶段写手,按已确认细纲、冻结事实和动态篇幅合同生成下一整章候选。作品需要续写下一章且输入合同完整时使用;不改规划、不把候选直接写入 Canonical。 disable-model-invocation: true --- @@ -13,19 +13,14 @@ disable-model-invocation: true - **章结构=字段合同**:`candidateBody` 只承载正文,不包含 frontmatter;Canonical 写入层依据 `meta/schemas/chapter.yaml` 与 `scene.yaml` 组装章结构。 - **行为约束=字段值**:文风(style 实例逐条)、人物言行(character.行事逻辑/说话方式/知情范围)、能力边界(power_system.代价限制)、地点规则(location.规则特例)——全部从上下文包字段读,不硬编。 -## 输入(`WriterCreativeInput v2`) +## 输入(冻结合同与两阶段投影) -可信 adapter 先校验完整的 `WriterContext v1`,再只通过 stdin 传入创作所需投影 `WriterCreativeInput v2`: +可信 adapter 先校验完整的 `WriterContext v1`。生产入口不会把完整上下文直接交给生成阶段,而是分两步投影: -- `fineOutline`:本章细纲硬骨架。 -- `narrativeState`:目标章前的叙事状态。 -- `factConstraints`:由卡索引和原文证据归纳出的事实约束。 -- `proseExcerpts`:用于连续性与叙事声音的历史正文摘录。 -- `patternReferences`:可参考的写作范式——每条给名字(name)、一句话摘要(summary)与写法要点(writingPoints);只供借鉴写法,不是事实约束。 -- `lengthContract`:给写手看的生成篇幅合同;生产续写为 4000–7000 汉字,目标 7000。 -- `styleConstraints`:文风约束;生产组装时还包含 `预防机器味` 生成的有限人感前置约束(规则/声音账指纹只留在完整 WriterContext,不投影给 writer)。 +1. 探索阶段只收到作品、目标章、候选版本、本轮人指令和只读工具白名单;它按需读取细纲、前文、叙事状态、实体事实、文风与已绑定范式,输出 `writer-exploration-manifest-v1`。 +2. 确定性回放按 manifest 重放只读工具,无模型参与;生成阶段收到 `two-phase-generation-v1`:`explorationMaterials`、`lengthContract`、`styleConstraints`、`humanInstruction`,以及仅供参考的探索笔记。正文事实只能来自 `explorationMaterials`。 -Writer 不接收 `runId`、权限信息、manifest、hash、候选版本、验收状态、实验臂、oracle 或目标章之后的内容,也不得自行检索;投影里没有的设定不应被当作已确认事实。 +生成阶段不接收 `runId`、权限信息、manifest、hash、候选版本、验收状态、实验臂、oracle 或目标章之后的内容,也不再调用工具。探索阶段没有读到的设定不得被当作已确认事实。 ## 功能约束 @@ -40,7 +35,7 @@ Writer 不接收 `runId`、权限信息、manifest、hash、候选版本、验 Dashboard 与人工生产入口统一调用 `scripts/produce_next_chapter.py`。该入口只负责编排本 Skill 已登记的冻结、检索、writer、detector、CAS、候选落库和人闸步骤;不提供自动 accept。运行 artifacts 仍由只读看板按 run_id 读取。 -- 写作节点的唯一执行形态是两阶段写手(写手合同不变,产出为 `candidateBody` 信封):`produce_next_chapter.py <章> --provider P --model M [--thinking T] [--instruction ...]`。探索阶段写作智能体带只读工具自主取材并产出探索清单;确定性回放按清单重放只读工具(无模型参与)得到写手实际依赖资料;生成阶段写作智能体无工具、单条成稿,生成输入只含回放资料与篇幅/文风合同,不含预组装上下文(`scripts/two_phase_writer.py`)。探索与生成各记独立派发运行,探索摘要落 `artifacts/-exploration-summary.json`;2026-08-23 候选 164 以该形态双门通过并经人采纳入正典。 +- 写作节点的唯一执行形态是两阶段写手(写手合同不变,产出为 `candidateBody` 信封):`produce_next_chapter.py <章> --provider P --model M [--work-id W] [--thinking T] [--instruction ...]`。探索阶段写作智能体带只读工具自主取材并产出探索清单;确定性回放按清单重放只读工具(无模型参与)得到写手实际依赖资料;生成阶段写作智能体无工具、单条成稿,生成输入只含回放资料与篇幅/文风合同,不含预组装上下文(`scripts/two_phase_writer.py`)。探索与生成各记独立派发运行,探索摘要落 `artifacts/-exploration-summary.json`;2026-08-23 候选 164 以该形态双门通过并经人采纳入正典。 - `provider`/`model` 必须显式传入(模型策略归角色合同与调用方,不从环境变量推断);直调链已按 2026-08-23 对照裁决退出创作生成,对照实验走独立入口 `scripts/run_contrast_writer.py`(产 `run_type=eval` 候选,四层机械不可接受)。 - 派发链的模型证据记在派发运行下,生产候选账本以显式 `writer_raw_ref` 关联,不双套记账;一章一组稳定会话(`writer-explore-work-ch` / `writer-gen-work-ch`,复用=继续原写作智能体)。 - 授权继续:管线停在 `AUTHORIZATION_REQUIRED` 时留痕 `artifacts/-authorization-request.json`;人授权后以 `--continue-from <前序 run_id>` 发起新运行,编排方按缺口补证重组上下文后继续。 @@ -63,7 +58,7 @@ Dashboard 与人工生产入口统一调用 `scripts/produce_next_chapter.py`。 ## 红线 -不调用工具,不读写文件,不持久化会话;细纲硬骨架不得删除、反转或提前回收;可以设计新设定但不得冒充已确认事实,不得自行给候选生成 hash、版本、验收或审查结论。 +探索阶段只调用任务包声明的只读工具,不直接访问数据库或文件;生成阶段零工具、单条成稿,不读写文件。两个阶段都不得改规划或正式内容;细纲硬骨架不得删除、反转或提前回收;可以设计新设定但不得冒充已确认事实,不得自行给候选生成 hash、版本、验收或审查结论。 ## 复利合同 diff --git a/muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py b/muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py index e744b10..e2ab8ea 100644 --- a/muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py +++ b/muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py @@ -14,11 +14,11 @@ → 停止并展示候选,等待用户明确选择改 / 丢弃 / 采纳 用法:.venv/bin/python muse/content/work/skills/generate/写下一章/scripts/produce_next_chapter.py [目标章号] - --provider

--model [--thinking T] [--instruction "本轮人指令原文"] + --provider

--model [--work-id W] [--thinking T] [--instruction "本轮人指令原文"] 写手唯一执行形态是两阶段框架派发(2026-08-23 对照裁决:直调链退出创作生成); --provider/--model 必须显式给出,不从环境变量推断。 缺省写下一章(库内最大章序 +1)。前置:目标章已建立、存在 confirmed 细纲,且门锚合同 -GATE_ANCHORS 已登记该章。 +已按目标作品与目标章登记。 --instruction:写入本轮输入第 7 项(人指令),经 styleConstraints 注入 writer; 与 05 §2.3 同序拼装合同对齐。正式采纳只由用户明确决定后调用 决定正文候选去留。 """ @@ -90,7 +90,7 @@ from run_registry import finish_run, start_run # noqa: E402 from check_writer_acceptance import AcceptanceError, check_writer_acceptance # noqa: E402 from acceptance_state import LiveStateError, build_live_acceptance_state # noqa: E402 -WORK_ID = 12 +DEFAULT_WORK_ID = 12 GATE_A_CONFIG = json.loads((REPO_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "回放评估正文质量" / "configs" / "writer-gate-a-deep-space-v1-cn-skills.json").read_text(encoding="utf-8")) @@ -110,57 +110,60 @@ SYSTEM_PROMPT_SHA256 = "sha256:" + hashlib.sha256(SYSTEM_PROMPT.encode("utf-8")) ARTIFACTS = REPO_ROOT / "docs" / "write-chapter" / "artifacts" -# 门锚合同按章登记:锚点是章级创作判断,any-hit 子串匹配。新章必须先登记再跑。 +# 门锚合同按作品+章登记:锚点是章级创作判断,any-hit 子串匹配。新章必须先登记再跑。 # 机械门(check_writer_candidate)只认这些子串,不认语义等价;必须投影给写手, # 否则写手只见细纲「完成第一次升级」却因禁抄长句而避开「升级」二字 → HARD_EVENT_MISSING。 -GATE_ANCHORS = { - 2: { - "requiredEvents": [ - {"requirementId": "event-1-isolation", - "anchors": ["隔离", "收押", "禁闭", "关押", "封锁"]}, - {"requirementId": "event-2-interrogation", - "anchors": ["审讯", "审问", "询问", "盘问", "讯问"]}, - {"requirementId": "event-3-conceal", - "anchors": ["隐瞒", "没有告诉", "没说", "没有说", "咽了回去", "沉默", "闭上嘴"]}, - {"requirementId": "event-4-hunger", - "anchors": ["饥饿", "渴望", "吞噬", "进食", "吃", "贪"]}, - ], - "requiredCharacters": ["林深", "何岚"], - "foreshadowingActions": [ - {"requirementId": "foreshadow-upgrade", - "anchors": ["异种核心", "融合", "升级"]}, - ], - "chapterEndHook": { - "requirementId": "hook-ch2", - "anchors": ["调令", "实战", "出击", "部署", "任务", "出征", "离不开", "不愿离开"], - "maxDistanceFromEnd": 900, +GATE_ANCHORS_BY_WORK = { + 12: { + 2: { + "requiredEvents": [ + {"requirementId": "event-1-isolation", + "anchors": ["隔离", "收押", "禁闭", "关押", "封锁"]}, + {"requirementId": "event-2-interrogation", + "anchors": ["审讯", "审问", "询问", "盘问", "讯问"]}, + {"requirementId": "event-3-conceal", + "anchors": ["隐瞒", "没有告诉", "没说", "没有说", "咽了回去", "沉默", "闭上嘴"]}, + {"requirementId": "event-4-hunger", + "anchors": ["饥饿", "渴望", "吞噬", "进食", "吃", "贪"]}, + ], + "requiredCharacters": ["林深", "何岚"], + "foreshadowingActions": [ + {"requirementId": "foreshadow-upgrade", + "anchors": ["异种核心", "融合", "升级"]}, + ], + "chapterEndHook": { + "requirementId": "hook-ch2", + "anchors": ["调令", "实战", "出击", "部署", "任务", "出征", "离不开", "不愿离开"], + "maxDistanceFromEnd": 900, + }, }, - }, - 3: { - # 接第2章结尾硬钩子(茧撕开舱门出击、要吃掉更强核心)。锚点 any-hit 子串匹配; - # requiredCharacters 只硬约束主角(避免过度约束触发 costly 重抽),其余靠事件锚点。 - "requiredEvents": [ - {"requirementId": "event-1-sortie", - "anchors": ["出击", "实战", "战斗", "交火", "搏杀", "拦截", "扑向", "战场"]}, - {"requirementId": "event-2-devour", - "anchors": ["吞噬", "吞食", "吃掉", "进食", "撕碎", "吸收", "吞下", "吞"]}, - {"requirementId": "event-3-upgrade", - "anchors": ["升级", "蜕变", "进化", "变强", "增强", "新的力量", "蜕变"]}, - {"requirementId": "event-4-pollution", - "anchors": ["黑纹", "污染", "扩散", "蔓延", "加深", "恶化"]}, - ], - "requiredCharacters": ["林深"], - "foreshadowingActions": [ - {"requirementId": "foreshadow-voice-merge", - "anchors": ["分不清", "像他自己", "脑内的声音", "低语", "渴望", "哪个念头", "另一个"]}, - ], - "chapterEndHook": { - "requirementId": "hook-ch3", - "anchors": ["深渊", "更深", "回应", "召唤", "更大", "下一", "不止", "饥饿", "注视", "凝视"], - "maxDistanceFromEnd": 900, + 3: { + # 接第2章结尾硬钩子(茧撕开舱门出击、要吃掉更强核心)。锚点 any-hit 子串匹配; + # requiredCharacters 只硬约束主角(避免过度约束触发 costly 重抽),其余靠事件锚点。 + "requiredEvents": [ + {"requirementId": "event-1-sortie", + "anchors": ["出击", "实战", "战斗", "交火", "搏杀", "拦截", "扑向", "战场"]}, + {"requirementId": "event-2-devour", + "anchors": ["吞噬", "吞食", "吃掉", "进食", "撕碎", "吸收", "吞下", "吞"]}, + {"requirementId": "event-3-upgrade", + "anchors": ["升级", "蜕变", "进化", "变强", "增强", "新的力量", "蜕变"]}, + {"requirementId": "event-4-pollution", + "anchors": ["黑纹", "污染", "扩散", "蔓延", "加深", "恶化"]}, + ], + "requiredCharacters": ["林深"], + "foreshadowingActions": [ + {"requirementId": "foreshadow-voice-merge", + "anchors": ["分不清", "像他自己", "脑内的声音", "低语", "渴望", "哪个念头", "另一个"]}, + ], + "chapterEndHook": { + "requirementId": "hook-ch3", + "anchors": ["深渊", "更深", "回应", "召唤", "更大", "下一", "不止", "饥饿", "注视", "凝视"], + "maxDistanceFromEnd": 900, + }, }, }, } +GATE_ANCHORS = GATE_ANCHORS_BY_WORK[DEFAULT_WORK_ID] def format_mechanical_gate_constraints(requirements: Mapping[str, Any]) -> list[str]: @@ -253,13 +256,22 @@ class ProductionSemanticRunner: "modelReceiptSha256": sha256_json(receipt_dict)} -def resolve_target_chapter(requested: int | None) -> int: +def resolve_gate_requirements(work_id: int, target_chapter: int) -> Mapping[str, Any]: + requirements = (GATE_ANCHORS_BY_WORK.get(work_id) or {}).get(target_chapter) + if requirements is None: + raise SystemExit( + f"作品 {work_id} 第{target_chapter}章门锚合同未登记,先补齐该作品该章锚点再跑。" + ) + return requirements + + +def resolve_target_chapter(requested: int | None, *, work_id: int) -> int: with connect(readonly=True) as conn: if requested is not None: return requested row = conn.execute( "SELECT COALESCE(MAX(order_no),0)+1 FROM muse_content_chapter " - "WHERE work_id=%s AND deleted=false", (WORK_ID,)).fetchone() + "WHERE work_id=%s AND deleted=false", (work_id,)).fetchone() return int(row[0]) @@ -294,21 +306,22 @@ def main(): dispatch_model = _take("--model") dispatch_thinking = _take("--thinking") continue_from = _take("--continue-from") + work_id_raw = _take("--work-id") if not dispatch_provider or not dispatch_model: raise SystemExit("生产写手必须显式给出 --provider 与 --model(两阶段框架派发)") + work_id = int(work_id_raw) if work_id_raw is not None else DEFAULT_WORK_ID args = [arg for arg in argv if not arg.startswith("--")] - target = resolve_target_chapter(int(args[0]) if args else None) + target = resolve_target_chapter(int(args[0]) if args else None, work_id=work_id) as_of = target - 1 - run_id = f"run-prod-work12-ch{target}-{uuid.uuid4().hex[:8]}" + run_id = f"run-prod-work{work_id}-ch{target}-{uuid.uuid4().hex[:8]}" generated_at = datetime.now(timezone.utc).isoformat() ARTIFACTS.mkdir(exist_ok=True) - if target not in GATE_ANCHORS: - raise SystemExit(f"第{target}章门锚合同未登记(GATE_ANCHORS),先登记锚点再跑。") + gate_requirements = resolve_gate_requirements(work_id, target) # 1) 已确认细纲(read-context 统一消费点)+ 前章全文基线(asOf 起连续四章;不足四章从第1章起) with connect(readonly=True) as conn: try: - fine_outline = load_confirmed_fine_outline(conn, work_id=WORK_ID, target_chapter=target) + fine_outline = load_confirmed_fine_outline(conn, work_id=work_id, target_chapter=target) except RetrievalError as exc: raise SystemExit(f"{exc}(目标章必须先建立并确认细纲)") first = max(1, as_of - 3) @@ -316,15 +329,15 @@ def main(): "SELECT c.order_no, b.id, b.revision, b.content_text FROM muse_content_chapter c " "JOIN muse_content_block b ON b.chapter_id=c.id AND b.deleted=false " "WHERE c.work_id=%s AND c.deleted=false AND c.order_no BETWEEN %s AND %s " - "ORDER BY c.order_no", (WORK_ID, first, as_of)).fetchall() - style_constraints = load_confirmed_style(conn, work_id=WORK_ID) - pattern_references = load_confirmed_pattern_bindings(conn, work_id=WORK_ID) + "ORDER BY c.order_no", (work_id, first, as_of)).fetchall() + style_constraints = load_confirmed_style(conn, work_id=work_id) + pattern_references = load_confirmed_pattern_bindings(conn, work_id=work_id) # 第 7 项人指令:与文风并列注入 styleConstraints,看板/raw 可回看 if human_instruction: style_constraints = list(style_constraints) + [f"本轮人指令:{human_instruction}"] print(f"本轮人指令已注入({len(human_instruction)} 字)") # 机械门锚点必须对写手可见(根因修复:#120 写了升级语义但未命中子串) - gate_lines = format_mechanical_gate_constraints(GATE_ANCHORS[target]) + gate_lines = format_mechanical_gate_constraints(gate_requirements) style_constraints = list(style_constraints) + gate_lines print(f"机械门锚点已注入写手约束({len(gate_lines)} 条)") recent_chapters = [{ @@ -345,7 +358,7 @@ def main(): # 1.5) 人感前置预防:规则/声音账先形成合同,再冻结进 WriterContext。 try: humanization_contract = build_prevention_contract( - f"work:{WORK_ID}", load_database=True + f"work:{work_id}", load_database=True ) humanization_contract["writer_constraints"] = render_writer_constraints(humanization_contract) prevention_receipt = persist_prevention(humanization_contract) @@ -358,7 +371,7 @@ def main(): # 2) 检索计划 + 执行(生产仓储;新书无卡诚实返空) token_budget = {"maxContextChars": 200000} plan = build_retrieval_plan( - run_id=run_id, work_id=WORK_ID, target_chapter=target, as_of=as_of, + run_id=run_id, work_id=work_id, target_chapter=target, as_of=as_of, fine_outline=fine_outline, card_index_version="knowledge-index-v1", prose_index_version="content-block-v1", token_budget=token_budget) retrieval = retrieve_writer_sources( @@ -382,12 +395,12 @@ def main(): "characterPositions": {}, "immediateSituation": "按细纲 chapterGoal 展开(上一章结尾状态见基线正文)。", } - authorization_snapshot = {"snapshotId": "auth-work12-production-v1", + authorization_snapshot = {"snapshotId": f"auth-work{work_id}-production-v1", "allowedPurpose": "production_generation", "verifiedAt": generated_at, "sourceVersion": "v1"} assembled = assemble_context( run_id=run_id, attempt=1, mode="production", purpose="production", - quality_policy_version="writer-production-v1", work_id=WORK_ID, + quality_policy_version="writer-production-v1", work_id=work_id, target_chapter=target, as_of=as_of, source_version="outline@v1", authorization_snapshot=authorization_snapshot, source_status="active", retrieval_plan=plan, retrieval_result=retrieval, fine_outline=fine_outline, @@ -411,7 +424,7 @@ def main(): detector_profile = build_semantic_detector_profile() semantic_runner = ProductionSemanticRunner(detector_profile, run_id=run_id) state_store = PostgresCasStateStore( - work_id=WORK_ID, target_chapter=target, creator="continuation") + work_id=work_id, target_chapter=target, creator="continuation") receipts_by_version: dict[int, Any] = {} candidates_by_version: dict[int, dict] = {} contexts_by_attempt: dict[int, dict] = {} @@ -422,7 +435,7 @@ def main(): """人感技能 3:每个候选先做只读诊断并自动落质量账;不在这里改正文。""" deai_artifact = run_diagnosis( - candidate_body, work_ref=f"work:{WORK_ID}", + candidate_body, work_ref=f"work:{work_id}", chapter_ref=f"chapter:{target}", mode="Audit", ) _dump(ARTIFACTS / f"{run_id}-ai-flavor-diagnosis-v{candidate_version}.json", deai_artifact) @@ -488,7 +501,7 @@ def main(): try: next_ctx = reassemble_writer_context_for_gaps( - context, gaps, attempt, work_id=WORK_ID) + context, gaps, attempt, work_id=work_id) except EvidenceReassembleError as exc: raise PipelineError( "PRODUCTION_EVIDENCE_REASSEMBLE_FAILED", @@ -508,7 +521,7 @@ def main(): "SELECT COALESCE(MAX(CASE WHEN candidate_version ~ '^[0-9]+$' " "THEN candidate_version::integer END),0) FROM example_candidate " "WHERE tenant_id=0 AND work_id=%s AND target_chapter=%s AND deleted=false", - (WORK_ID, target)).fetchone() + (work_id, target)).fetchone() initial_candidate_version = int(max_version_row[0]) + 1 if continue_from: @@ -517,7 +530,7 @@ def main(): request = json.loads(request_path.read_text(encoding="utf-8")) except (OSError, ValueError) as exc: raise SystemExit(f"授权请求读取失败: {request_path}: {exc}") - if request.get("workId") != WORK_ID or request.get("targetChapter") != target: + if request.get("workId") != work_id or request.get("targetChapter") != target: raise SystemExit("授权请求与本次作品/章不匹配,拒绝继续") gaps = request.get("evidenceGaps") or [] if not gaps: @@ -526,7 +539,7 @@ def main(): print(f"[授权继续] 前序运行 {continue_from}:命中缺口 {len(gaps)} 项," f"本次以补证后上下文(attempt={writer_context['attempt']})继续。") - start_run(run_id=run_id, work_id=WORK_ID, target_chapter=target, + start_run(run_id=run_id, work_id=work_id, target_chapter=target, trigger_detail={"stage": "writer-production-pipeline", "contextSha256": writer_context["contextSnapshot"]["contextSha256"], **({"continueFrom": continue_from} if continue_from else {}), @@ -535,7 +548,7 @@ def main(): try: pipeline_result = run_writer_pipeline( context=writer_context, - requirements=GATE_ANCHORS[target], + requirements=gate_requirements, writer=production_writer, evidence_provider=production_evidence_provider, semantic_detector=production_semantic_detector, @@ -571,7 +584,7 @@ def main(): _dump(ARTIFACTS / f"{run_id}-authorization-request.json", { "schemaVersion": "authorization-request-v1", "runId": run_id, - "workId": WORK_ID, + "workId": work_id, "targetChapter": target, "humanInstruction": human_instruction, "evidenceGaps": gaps, diff --git a/muse/lifecycle/context/skills/准备任务上下文/SKILL.md b/muse/lifecycle/context/skills/准备任务上下文/SKILL.md index de4bb5d..14c5de4 100644 --- a/muse/lifecycle/context/skills/准备任务上下文/SKILL.md +++ b/muse/lifecycle/context/skills/准备任务上下文/SKILL.md @@ -60,12 +60,12 @@ writer 的 `factConstraints=[]` 在冻结读取确实没有可确认事实时合 ## 回显与存储 - 安全回显只包含来源 ID/版本、章号、字符数、裁剪原因、状态和 hash,不包含原文、完整 prompt/response 或供应商原始响应。 -- 需要保留的 raw 输入、prompt、response、候选和 evaluator-only oracle 只能进入仓库外受控 raw vault,受显式授权、租约、保留期和清理回执约束。 +- 需要保留的 raw 输入、prompt、response、候选和 evaluator-only oracle 以 PostgreSQL raw 表为正式留痕,走单独表与访问控制。仓外受控 raw vault 只可作为运行期临时暂存或可选备份,须有租约、保留期和清理回执,不得替代库内权威。 - 不生成或读取旧文件式上下文;PostgreSQL Canonical 数据与冻结回执才是运行事实。 ## 红线 -- 模型不得自行访问数据库、搜索卡、回读文件或扩张检索计划。 +- 上下文组装器不把数据库、文件系统或检索计划控制权交给模型。获得任务包授权的探索智能体可以调用白名单只读工具按需检索;工具层负责限定表与版本范围、阻断未来信息并把读取写入事件账本。智能体不得绕过工具直接访问数据库或文件,也不得自行扩张白名单。 - 人感合同存在但 work_ref/规则指纹不合法时,组装器失败关闭;缺失时保留规则为空的诚实合同,不得静默退回通用「真人文风」。 - 不得把卡摘要当正文替代品,不得因为有卡减少历史原文检索。 - 不得把完整 WriterContext、raw 路径、授权密钥、真实实验臂或未来信息塞给模型。 diff --git a/muse/lifecycle/flow/chains/README.md b/muse/lifecycle/flow/chains/README.md index cb5ae24..791e714 100644 --- a/muse/lifecycle/flow/chains/README.md +++ b/muse/lifecycle/flow/chains/README.md @@ -16,12 +16,12 @@ agent 的提示词按**变化轴**拆三段,不做"一个 agent 一个大 prom | scenario | 功能 skill | 槽位/agent | purpose | 保护节点序列(简化) | 状态 | |---|---|---|---|---|---| -| continuation 续写 | `写下一章` | 写作→writer | generation | 准备任务上下文→无工具 writer→机械门→语义 detector→Shadow→用户三决策→accept_preflight→正式写入→异步抽取 | 生产链已闭环:机械门+真实语义 detector+持久 CAS 链+accept_preflight+正式写入(write_canonical 单事务,含已批准事实增量与投影登记);语义缺口补证重组装已接(production_evidence_reassemble);章后抽取的异步执行未建(抽取投影只登记 pending) | +| continuation 续写 | `写下一章` | 写作→writer | generation | 准备任务上下文→writer 白名单探索→确定性回放→无工具生成→AI 味诊断→机械门→语义 detector→Shadow→用户三决策→accept_preflight→正式写入→异步抽取 | 作品 12 第 2/3 章样本链已闭环:两阶段写手+机械门+真实语义 detector+持久 CAS 链+accept_preflight+正式写入(write_canonical 单事务,含已批准事实增量与投影登记);生产入口已支持 `--work-id` 显式指定作品,语义缺口补证重组装已接(production_evidence_reassemble);门锚仍按作品+章节登记,章后抽取异步执行未建(抽取投影只登记 pending) | | rewrite 改写 | `重写选段` | 写作→writer | generation | 同上+expectedRevision 核对 | 已建 | | expansion 扩写 | `扩写场景` | 写作→writer | generation | 同 continuation | 已建 | | polish 润色 | `润色正文` | 写作→writer | generation | 同 continuation(只动表达层) | 已建 | -| setting_init 作品设定初始化 | `完善故事基础设定` | 规划→planner | planning | 用户冻结根设定与对话→隔离候选→离线机械门→用户选择→交给 planning | 手工前置流程首建;候选不落库、不进 Canonical | -| planning 规划 | `制定作品规划` | 规划→planner | planning | 准备任务上下文(planning 视图)→槽位→用户确认(决定正文候选去留) | 已建 | +| setting_init 作品设定初始化 | `完善故事基础设定` | 规划→planner | planning | 用户冻结根设定与对话→隔离候选→离线机械门→用户选择→选定交接→planning 写 setting Shadow | 手工前置流程首建;比较候选不落库、不进生成上下文;选中不等于 confirmed | +| planning 规划 | `制定作品规划` | 规划→planner | planning | 准备任务上下文(planning 视图)→槽位→persist_planning 写 Shadow→用户确认翻 confirmed | 已建 | | fine_outline 细纲规划 | `规划下一章` | 规划→planner | planning | 准备任务上下文(fine_outline 冻结视图)→槽位→核对内容一致性→评估内容质量 | 评测版首建(2026-07-19) | | full_parse 拆书 | `拆解书稿` | 分析→extractor | extraction | 导入书稿 分章→逐章槽位→访问数据库 落 draft→管理员确认(G3 门) | 已建;B2 PG 版首验 | | ai_flavor_capture AI 味案例回填/反馈 | `记录机器味案例` | 检测→detector | detection | 作品/创作反馈→检测完成自动落库→hash 与位置门→Shadow 案例卡 | 已建;默认写入 muse-example,`--offline` 仅作显式离线回放 | diff --git a/muse/sot/domains/05-创作流程领域.md b/muse/sot/domains/05-创作流程领域.md index 1f193a4..e48171b 100644 --- a/muse/sot/domains/05-创作流程领域.md +++ b/muse/sot/domains/05-创作流程领域.md @@ -14,21 +14,23 @@ 本领域拥有这五阶段的**顺序、进入/退出条件和门禁**,不拥有各阶段产物的字段合同与存储表结构——字段权威在 [`muse/content/meta/schemas/`](../../content/meta/schemas/README.md),存储与确认链分别在 [01-作品领域](01-作品领域.md)、[02-实体领域](02-实体领域.md)、[03-范式领域](03-范式领域.md),本节只引用、不重复定义。 -两条贯穿五阶段的硬合同(均为既有合同,本节只引用): +贯穿五阶段的硬合同(均为既有合同,本节只引用): -- **横切总闸**:一切规划候选先落 Shadow,经用户确认翻 Confirmed 后才进入生成上下文(Shadow/Canonical 双轨,见 [架构-02](../../../../design-docs/架构-02-核心数据结构与双轨模型.md))。 +- **横切总闸**:一切正式规划候选先落 Shadow,经用户确认翻 Confirmed 后才进入生成上下文(Shadow/Canonical 双轨,见 [架构-02](../../../../design-docs/架构-02-核心数据结构与双轨模型.md))。 +- **阶段 0 探索例外**:`完善故事基础设定` 产出的多案比较稿属于正式规划之前的仓内探索材料,只留在用户指定的设计文档与候选目录,不进 PostgreSQL,也不得进入生成上下文。用户选定方向并通过 `assert_selection_handoff.py` 后,由 `制定作品规划` 把选定内容重写为 `setting` Shadow;该行经用户确认成为 Confirmed,才算阶段 0 正式退出。候选被选中不等于规划已确认。 - **上层约束下层**:大纲派生卷纲、卷纲派生细纲;下层规划不得与已确认的上层规划相悖,冲突时以下层退回为准。 ### 阶段定义 -除特别注明外,各阶段规划产出都经 `persist_planning` 落 `example_planning_section`(默认 `state='shadow'`),用户确认后翻 `confirmed`。 +阶段 0 的多案比较稿按上面的探索例外处理;选定方向的正式 `setting` 与阶段 1–4 的规划产出都经 `persist_planning` 落 `example_planning_section`(默认 `state='shadow'`),用户确认后翻 `confirmed`。 **阶段 0 · 定盘** - 进入条件:作品已创建(作品行存在,见 [01-作品领域](01-作品领域.md))。 -- 产出:`work_core`(题材定位 / 核心卖点 / 主题立意 / 基调 / 禁区 / 核心悬念 / 谜底与真相 / 结局方向 / 目标读者,字段权威见 `muse/content/meta/schemas/work_core.yaml`)+ `novel_work` 的篇幅目标(目标章数 × 单章字数区间 × 分卷数,见 `muse/content/meta/schemas/novel_work.yaml`)。落 `section_type='setting'`。 +- 探索产出:冻结根设定后生成可比较候选;候选只供用户选方向,不是 Shadow,也不是正式内容。统合多案仍只得到一份待选候选。 +- 正式产出:通过选定交接门后,`制定作品规划` 按 `work_core`(题材定位 / 核心卖点 / 主题立意 / 基调 / 禁区 / 核心悬念 / 谜底与真相 / 结局方向 / 目标读者,字段权威见 `muse/content/meta/schemas/work_core.yaml`)和 `novel_work` 的篇幅目标(目标章数 × 单章字数区间 × 分卷数,见 `muse/content/meta/schemas/novel_work.yaml`)生成 `section_type='setting'` Shadow。 - 机械门禁:**篇幅目标三要素齐全**——当前为文档纪律,待升级为落库校验。 -- 退出条件:`work_core` 九字段与篇幅目标三要素齐备且用户确认(`confirmed`)。 +- 退出条件:用户选定记录通过交接门,且 `work_core` 九字段与篇幅目标三要素齐备的 `setting` 已由用户确认(`confirmed`)。 **阶段 1 · 大纲 / 卷纲** @@ -124,7 +126,7 @@ 人决策才发生内容变化:要不要生成/改一版规划草稿 → 要不要 confirmed 【节点 W · 生成正文】 - 自动:prevent 合同装配(约束投影,不改正文);机械门;语义门;diagnose 报告; + 自动:prevent 合同装配(约束投影,不改正文);写手探索与确定性回放;diagnose 报告;机械门;语义门; 方法只读检查报告 人决策才发生内容变化:要不要让写手产/改候选草稿 → 要不要 revise → 要不要 accept 进正式正文 @@ -168,7 +170,7 @@ ### 2.3 交互回合合同(节点 W) -每一轮输入拼装**顺序固定**;第 2 轮及以后只在第 7 项写入你的上一轮原话,1–6 与第 1 轮同序。 +每一轮的**来源优先级与交互位置固定**;这不是把 1–6 全量拼成一包直接塞给生成阶段。探索阶段按任务包白名单读取所需材料并产出清单,确定性回放按清单重取材料,生成阶段只接收回放材料、篇幅合同、文风约束与本轮人指令。第 2 轮及以后只替换第 7 项为你的上一轮原话,1–6 的来源范围和优先级不变。 | 序 | 输入项 | 说明 | |---|---|---| @@ -177,7 +179,7 @@ | 3 | 前章正式正文基线 | 连续 as_of 起若干章 | | 4 | 文风 + 已绑定范式 | 有则注入 | | 5 | prevent 约束投影 | 不改正文 | -| 6 | 方法合同(只读) | 装载 + 检查报告;待建 | +| 6 | 方法合同(只读) | 允许探索阶段按需装载;自动检查报告待建 | | 7 | **本轮人指令** | 第 1 轮可为空(「写第 N 章」);之后为「改:…」原文 | | 输出块 | 说明 | @@ -200,7 +202,7 @@ | 节点 | 必用 | 可选(自动报告) | 人授权才用 | |---|---|---|---| | P 规划 | `准备任务上下文`、`制定作品规划` / `规划下一章` | 方法只读检查;`核对内容一致性` | 规划草稿生成与 `confirmed` | -| W 正文 | `预防机器味`→`准备任务上下文`→`写下一章`→机械门→语义→`诊断机器味`→Shadow | 方法只读检查;`评估内容质量`(生产待建) | 「写/改」产候选;`修正正文机器味` / `润色正文` / `重写选段`;`决定正文候选去留` | +| W 正文 | `预防机器味`→`准备任务上下文`→写手探索→确定性回放→无工具生成→`诊断机器味`→机械门→语义→Shadow | 方法只读检查;`评估内容质量`(生产待建) | 「写/改」产候选;`修正正文机器味` / `润色正文` / `重写选段`;`决定正文候选去留` | | A 章后 | (accept 触发)下游草稿:`抽取章节知识`、案例/规则候选登记 | lesson `proposed`;只读汇总 | `确认知识草稿`;规则激活;声音账定版;下一章开写 | 参照方法 Skill(`打磨小说语言` 等)不进 `meta/chains`;挂在 P/W「可选装载」,出卡升公共范式仍走复利批次 3 人闸。 @@ -266,6 +268,8 @@ DRAFT/CHECKING/PASSED -> DISCARDED(用户明确决策) 写手执行的唯一生产形态是两阶段写手(`produce_next_chapter.py <章> --provider P --model M`):探索阶段派发写作智能体(只读工具集)自主取材(细纲、前文、文风、范式、实体)、产出探索清单;确定性回放按清单重放只读工具(无模型参与),得到写手实际依赖的材料;生成阶段无工具派发、单次成稿,生成输入只含回放材料与篇幅/文风合同,不含全量预组装。探索与生成使用独立会话、各记独立派发运行,写手事实只来自它探索到的材料;探索清单与摘要落运行工件,探索轨迹与依赖清单进事件账本,是创作台链路透视的数据源。探索与生成分离的原因:单阶段同会话形态下,长篇生成会被多回合探索挤占输出空间导致正文碎片化(2026-08-23 烟测实证)。该形态已于 2026-08-23 生产烟测双门通过并经人采纳进正典;同源对照实验裁决直调链退出创作生成(见 `07-Agent与Skill领域`)。 +当前入口的覆盖范围仍以验证样本为主:`produce_next_chapter.py` 已支持 `--work-id` 显式指定作品,不再把作品号硬编码在执行入口、运行编号和授权快照里;但门锚仍按作品+章节登记,当前只为作品 12 的第 2、3 章备齐样本锚点。未登记门锚的作品或章节会在模型调用前失败关闭。两阶段编排、状态链和作品参数化已经落地,门锚通用化仍待建。 + ## 6. 运行与落库 - 正式内容和候选都在 PostgreSQL 内;Git 只管代码与文档,不承载正式内容。 diff --git a/muse/sot/创作周期与Skill导读.md b/muse/sot/创作周期与Skill导读.md index 0849921..e7ec3ce 100644 --- a/muse/sot/创作周期与Skill导读.md +++ b/muse/sot/创作周期与Skill导读.md @@ -118,7 +118,7 @@ Skill 还有两个实现形态: 0 1 2 3 4 ``` -每步产物先落 Shadow,你确认后才变 Confirmed,才允许进入下一步的生成上下文。下层不得跟已确认的上层打架。 +正式规划产物先落 Shadow,你确认后才变 Confirmed,才允许进入下一步的生成上下文。阶段 0 的多案比较稿是唯一例外:它只供选方向,不入库;选定方向必须经 `制定作品规划` 写成 `setting` Shadow 并确认,才算定盘完成。下层不得跟已确认的上层打架。 ### 章级:三个节点 @@ -128,7 +128,7 @@ Skill 还有两个实现形态: 节点 P 规划 → 节点 W 正文 → 节点 A 章后 ``` -写第 N 章时围着这三节点转。节点 W 喂给写手的顺序写死: +写第 N 章时围着这三节点转。节点 W 的来源优先级写死,但当前两阶段写手不会把这些内容全量预拼后直接交给生成阶段:探索阶段按白名单取材,确定性回放重取所选材料,生成阶段只看回放材料与篇幅、文风合同。 1. 库事实(作品 / 目标章 / 冻结点) 2. 已确认细纲 @@ -183,13 +183,13 @@ flowchart TD ### 阶段 0 · 定盘(节点 P) -**要完成**:这本书是什么、写给谁、禁区在哪、篇幅目标(目标章数 × 单章字数 × 分卷数)。九个核心字段齐,你确认后才能往下。 +**要完成**:先从多案中选定方向,再把这本书是什么、写给谁、禁区在哪、篇幅目标(目标章数 × 单章字数 × 分卷数)写成正式 `setting`。九个核心字段齐且正式规划已确认,才能往下。 功能链:`setting_init` → [完善故事基础设定](../lifecycle/flow/skills/book/完善故事基础设定/SKILL.md) → 规划师。 | Skill | 意图 | 规则 | 工具 / 方法 | |---|---|---|---| -| [完善故事基础设定](../lifecycle/flow/skills/book/完善故事基础设定/SKILL.md) | 固化根设定,按固定三级章节树出可比较候选 | 候选不落库、不进 Canonical;你选完才交给规划 | `validate_candidates.py`、`assert_selection_handoff.py`;合同在 `references/candidate-contract.md` | +| [完善故事基础设定](../lifecycle/flow/skills/book/完善故事基础设定/SKILL.md) | 固化根设定,按固定三级章节树出可比较候选 | 候选不落库、不进生成上下文;选中只完成方向交接,不等于规划确认 | `validate_candidates.py`、`assert_selection_handoff.py`;合同在 `references/candidate-contract.md` | | [合并故事方案](../lifecycle/flow/skills/book/合并故事方案/SKILL.md) | 多案逐章合成一案 | 一级章节一个新代理;根设定优先 | `serial_merge.py` | | [提炼故事概念](../../.agent/skills/规划/提炼故事概念/SKILL.md) | 把「我想写 X」升级成能撑长篇的疑问 | idea 是陈述,concept 是疑问;四问(新鲜 / 角度 / 冲突 / 可撑长),可撑长必须过 | 无脚本。见 [方法:概念设计](#提炼故事概念-概念设计) | @@ -291,7 +291,7 @@ flowchart TD → Shadow 候选给你看 ``` -当前实现仍走确定性装配链(`预防机器味 → 准备任务上下文 → 写下一章 → 机械门 → 核对内容一致性 → 诊断机器味 → Shadow`),写手无工具、收预组装上下文;智能体化切换按整体收敛总 plan 阶段 E 推进,两条描述以角色合同与 05 领域 §5 为准。 +当前生产实现已经切到两阶段写手:`预防机器味 → 冻结任务边界 → 写手带白名单工具探索 → 确定性回放所选材料 → 写手无工具单次成稿 → 诊断机器味 → 机械门 → 核对内容一致性 → Shadow`。探索与生成各用独立会话并分别留痕;生成阶段不接收全量预组装上下文。当前入口已支持 `--work-id` 显式指定作品,不再把作品号硬编码在执行入口、运行编号和授权快照里;但门锚仍按作品+章节登记,当前只备齐作品 12 的第 2、3 章样本锚点,所以还不是任意作品、任意章节的通用入口。 你说「写第 N 章」= 授权本轮产 Shadow。 你说「改:……」= 原话进入下一轮第 7 项,不入库。 @@ -659,6 +659,7 @@ Gate A/B、A/B/C 三臂、参考书标准答案,只属于离线验收。评测 - 文风八字段的书级抽取尚未建;当前注入的是设定行一句话文风。 - 阶段 0–1 的字数、比例、四要素校验仍是文档纪律。 - 设定全书闭环与设定×章消费台账待建。 +- 生产入口已支持 `--work-id` 显式指定作品;门锚仍只登记作品 12 的第 2、3 章,门锚通用化待建。 --- diff --git a/muse/技能目录.md b/muse/技能目录.md index 96c0e4d..83abf1c 100644 --- a/muse/技能目录.md +++ b/muse/技能目录.md @@ -60,7 +60,7 @@ | 技能名 | 技能文件 | 技能说明 | |---|---|---| -| 写下一章 | [SKILL.md](content/work/skills/generate/写下一章/SKILL.md) | 按已确认细纲、冻结事实和动态篇幅合同生成下一整章候选。作品需要续写下一章且输入合同完整时使用;不自行检索、不改规划、不把候选直接写入 Canonical。 | +| 写下一章 | [SKILL.md](content/work/skills/generate/写下一章/SKILL.md) | 通过“白名单探索→确定性回放→无工具生成”两阶段写手,按已确认细纲、冻结事实和动态篇幅合同生成下一整章候选。作品需要续写下一章且输入合同完整时使用;不改规划、不把候选直接写入 Canonical。 | | 扩写场景 | [SKILL.md](content/work/skills/generate/扩写场景/SKILL.md) | 在既有场景内补充动作链、对话潜台词、感官细节和环境互动。用户认为某个场景过薄并明确要求扩写时使用;不新开场景、不改落点、不夹带新设定。点名改情节/翻案归 重写选段;只修语病/标点/节奏归 润色正文;AI 味须先 诊断机器味,本槽不得绕过。 | | 润色正文 | [SKILL.md](content/work/skills/generate/润色正文/SKILL.md) | 修正候选或既有正文的错字、语病、标点、节奏和角色声音指纹(非规则级去 AI 味)。用户只要求改善表达层时使用;不得改变情节事实、场景结构或对白语义。场景加厚归 扩写场景;点名改范围/翻案归 重写选段;AI 味检测与修订归 诊断机器味 → 修正正文机器味,本 Skill 不得自称去 AI 味入口。 | | 重写选段 | [SKILL.md](content/work/skills/generate/重写选段/SKILL.md) | 按用户意见重写指定段落或场景,并校验范围、事实锚和版本。用户明确点名修改范围时使用;范围外原文不动,不顺手改规划或知识卡。场景过薄只加厚归 扩写场景;只修表达层归 润色正文;AI 味须先 诊断机器味,本槽不得绕过。 | diff --git a/tests/skills/写下一章/test_gate_anchor_projection.py b/tests/skills/写下一章/test_gate_anchor_projection.py index b768b8e..7815257 100644 --- a/tests/skills/写下一章/test_gate_anchor_projection.py +++ b/tests/skills/写下一章/test_gate_anchor_projection.py @@ -35,6 +35,13 @@ class GateConstraintProjectionTests(unittest.TestCase): self.assertIn("变强", blob) self.assertIn("机械门验收", blob) + def test_resolve_gate_requirements_by_work_and_chapter(self) -> None: + requirements = self.entry.resolve_gate_requirements(12, 3) + self.assertEqual(requirements["requiredCharacters"], ["林深"]) + with self.assertRaises(SystemExit) as ctx: + self.entry.resolve_gate_requirements(99, 3) + self.assertIn("作品 99 第3章门锚合同未登记", str(ctx.exception)) + def test_missing_event_group_still_lists_characters(self) -> None: lines = self.entry.format_mechanical_gate_constraints( {