For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 修复 init→plan→write→plan→write 全链路中 7 个使用者视角的断裂问题,确保题材从 init 到裁决层的流通、story-system 在正确时机触发、plan 跨卷时能感知已写内容。
Architecture: 围绕"题材是 init 写入 state.json 的唯一真源"这个核心决策,从数据层(CSV 别名补齐)到流程层(SKILL.md 规范化)逐步修复。
Tech Stack: CSV (UTF-8 BOM), Python CLI, Markdown prompt files
已确认决策:
问题: init 支持的题材名(修仙、系统流、高武、西幻等)与裁决表的题材名(东方仙侠、西方奇幻等)不匹配,导致裁决层对部分题材不生效。
Files:
webnovel-writer/references/csv/裁决规则.csvModify: webnovel-writer/references/csv/题材与调性推理.csv
[ ] Step 1: 建立 init 题材 → 裁决题材的映射
init SKILL.md 第 110-113 行列出的题材集合:
玄幻修仙类:修仙 | 系统流 | 高武 | 西幻 | 无限流 | 末世 | 科幻
都市现代类:都市异能 | 都市日常 | 都市脑洞 | 现实题材 | 黑暗题材 | 电竞 | 直播文
言情类:古言 | 宫斗宅斗 | 青春甜宠 | 豪门总裁 | ...
特殊题材:规则怪谈 | 悬疑脑洞 | 悬疑灵异 | 历史古代 | 历史脑洞 | ...
映射到现有 7 个裁决题材:
| init 题材名 | → 裁决题材 |
|---|---|
| 修仙、仙侠 | 东方仙侠 |
| 西幻、西方奇幻 | 西方奇幻 |
| 末世、科幻 | 科幻末世 |
| 都市异能、都市脑洞、现实题材 | 都市日常 |
| 都市修真、现代修真 | 都市修真 |
| 高武、都市异能(高武向) | 都市高武 |
| 历史古代、历史脑洞 | 历史古代 |
| 系统流、无限流 | 东方仙侠(fallback,多为修仙变体) |
不在映射中的(言情类、规则怪谈、悬疑等)暂无裁决行,走空裁决 fallback。
每行的「关键词」列追加 init 题材名:
| 裁决题材 | 当前关键词 | 追加 |
|---|---|---|
| 西方奇幻 | 西方奇幻\|奇幻 |
\|西幻 |
| 东方仙侠 | 东方仙侠\|仙侠 |
\|修仙\|系统流\|无限流 |
| 科幻末世 | 科幻末世\|末世\|科幻 |
(已覆盖) |
| 都市日常 | 都市日常\|都市 |
\|都市脑洞\|现实题材\|黑暗题材 |
| 都市修真 | 都市修真\|修真\|现代修真 |
(已覆盖) |
| 都市高武 | 都市高武\|高武\|都市异能 |
(已覆盖) |
| 历史古代 | 历史古代\|历史\|古代 |
\|历史脑洞 |
编辑 CSV 文件,在对应行的「关键词」列追加。
路由表 题材与调性推理.csv 当前 8 行是流派(退婚流、规则怪谈等),不是题材大类。不改现有行。
但路由表目前缺少"东方仙侠""西方奇幻""科幻末世"等大类的路由行。当用户 genre 是"修仙"时,路由表的 _route() 可能匹配不上任何行(因为现有行都是具体流派)。
需要确认:路由表是否需要补"大类"行?检查 _route() 的 fallback 逻辑——如果匹配不上,用 --genre 参数做 explicit_genre_fallback,走默认推荐表。这个 fallback 够用。
结论:路由表不改。裁决表补别名即可。路由匹配不上时 fallback 到默认推荐表 + 裁决表仍能通过 _load_reasoning(genre) 匹配到。
[ ] Step 4: 运行测试确认
cd "D:\wk\novel skill\webnovel-writer\webnovel-writer" && python -m pytest scripts/data_modules/tests/test_csv_config.py scripts/data_modules/tests/test_reasoning_engine.py -v --tb=short
[ ] Step 5: Commit
cd "D:\wk\novel skill\webnovel-writer" && git add webnovel-writer/references/csv/裁决规则.csv && git commit -m "fix: expand reasoning table genre aliases to cover init genre names"
问题: write SKILL.md 调 story-system "{chapter_goal}" 时 {chapter_goal} 来源不明,导致路由质量不可控。
决策: genre 从 state.json 读取,作为唯一真源。query 参数改为章纲目标(用于 CSV 检索),genre 参数固定从 state.json 取。
Files:
webnovel-writer/skills/webnovel-write/SKILL.mdModify: webnovel-writer/skills/webnovel-plan/SKILL.md
[ ] Step 1: 修改 write SKILL.md 准备阶段的 story-system 调用
当前(第 141-143 行):
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" \
story-system "{chapter_goal}" --chapter {chapter_num} --persist --emit-runtime-contracts --format both
改为:
# 从 state.json 读取题材(唯一真源)
GENRE="$(python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" state get-field --field project.genre)"
# 从章纲提取本章目标作为检索 query(若无章纲则用题材兜底)
CHAPTER_GOAL="{从章纲提取的本章目标,如'韩立进入坊市试探消息真伪'}"
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" \
story-system "${CHAPTER_GOAL}" --genre "${GENRE}" --chapter {chapter_num} --persist --emit-runtime-contracts --format both
在这段命令前加说明:
**genre 参数规范**:
- `--genre` 必须从 `state.json` 的 `project.genre` 读取,不得手动填写
- 第一个位置参数(query)填本章章纲的"目标"字段内容,用于 CSV 知识检索
- 若章纲无明确目标,fallback 到 `"{题材} 第{chapter_num}章"`
当前(第 59-61 行):
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${WORKSPACE_ROOT}" \
story-system "{chapter_goal}" --chapter {chapter_num} --persist --emit-runtime-contracts --format both
同样改为带 --genre 的规范形式。
[ ] Step 3: 确认 state get-field CLI 命令存在
grep -n "get-field" webnovel-writer/scripts/data_modules/webnovel.py
如果不存在,需要补一个简单的 state 子命令来读取任意 JSON path。或者用 jq/python 一行脚本替代:
GENRE="$(python -X utf8 -c "import json; s=json.load(open('${PROJECT_ROOT}/.webnovel/state.json')); print(s.get('project',{}).get('genre',''))")"
[ ] Step 4: Commit
git add webnovel-writer/skills/webnovel-write/SKILL.md webnovel-writer/skills/webnovel-plan/SKILL.md
git commit -m "fix: standardize story-system genre input from state.json as sole source"
问题: init 完成后 .story-system/ 目录不存在,plan 的卷级规划阶段缺少调性/禁忌参照。
Files:
Modify: webnovel-writer/skills/webnovel-init/SKILL.md
[ ] Step 1: 在 init SKILL.md 的"执行生成"段落末尾追加 story-system 触发
在"3) Patch 总纲"之后、"验证与交付"之前,新增:
### 4) 生成写前合同树(Story System 初始化)
init 完成后,立即生成 MASTER_SETTING,让后续 plan 有调性/禁忌参照:
bash GENRE="$(python -X utf8 -c "import json; s=json.load(open('{project_root}/.webnovel/state.json')); print(s.get('project',{}).get('genre',''))")"
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" \ story-system "${GENRE}" --genre "${GENRE}" --persist --format json
说明:
- 此时不传 `--chapter`,只生成 `MASTER_SETTING.json` 和 `anti_patterns.json`
- 不传 `--emit-runtime-contracts`(还没有卷/章级数据)
- plan 阶段拆到具体章节时再生成 volume/chapter/review 合同
在验证检查中新增:
test -f "{project_root}/.story-system/MASTER_SETTING.json"
在成功标准中新增:
.story-system/MASTER_SETTING.json 存在且 route.primary_genre 非空
[ ] Step 3: Commit
git add webnovel-writer/skills/webnovel-init/SKILL.md
git commit -m "feat: init triggers story-system to generate MASTER_SETTING after project creation"
问题: chapter_brief.json 的 chapter_focus 是从 CSV 检索结果凑的,跟实际章纲无关,误导 context-agent。
决策: chapter_brief 只承载裁决/路由元数据。章纲是最高权重(仅次于用户意见),由 context-agent 直接读取。
Files:
webnovel-writer/agents/context-agent.mdModify: webnovel-writer/skills/webnovel-write/SKILL.md
[ ] Step 1: 在 context-agent.md 的"Story System 主链"段落明确权重
在写前真源列表后新增权重说明:
**数据权重(高→低)**:
1. 用户明确要求
2. 大纲/章纲原文(`大纲/第X卷-详细大纲.md` 中的本章内容)
3. Story Contracts 中的 `MASTER_SETTING`(题材、调性、核心禁忌)
4. `chapter_{NNN}.json` 的 `reasoning` 字段(裁决层的风格/节奏/毒点建议)
5. accepted `CHAPTER_COMMIT`(写后事实)
6. CSV 检索结果(创作参考,不覆盖大纲)
`chapter_{NNN}.json` 的 `chapter_focus` 字段仅为 CSV 检索派生的参考,不代表本章实际目标。本章目标以章纲原文为准。
在第 146-148 行的合同树说明后加:
**注意**:`.story-system/chapters/chapter_{NNN}.json` 的 `chapter_focus` 是 CSV 检索派生的参考建议,不是本章的实际目标。本章目标以 `大纲/第X卷-详细大纲.md` 中的章纲原文为最高权重。`chapter_{NNN}.json` 的核心价值是 `reasoning` 字段中的裁决元数据(风格优先级、节奏策略、反模式)。
[ ] Step 3: Commit
git add webnovel-writer/agents/context-agent.md webnovel-writer/skills/webnovel-write/SKILL.md
git commit -m "docs: clarify chapter_brief carries reasoning metadata, outline is authority"
问题: plan 第2卷时不读 commit 历史、summaries、实体状态,导致章纲可能与已写内容矛盾。
决策: plan 步骤 1 加载大纲 + 用户意见 + 已有剧情状态 + CSV 检索。
Files:
Modify: webnovel-writer/skills/webnovel-plan/SKILL.md
[ ] Step 1: 扩展 plan Step 1 的数据加载
当前 Step 1(第 97-113 行)只读 state.json 和总纲。改为:
### Step 1:加载项目数据并确认前置条件
**必须加载**:
bash
cat "$PROJECT_ROOT/.webnovel/state.json"
cat "$PROJECT_ROOT/大纲/总纲.md"
**已有卷的剧情状态**(跨卷规划时必须加载):
若已有已完成卷(`.webnovel/summaries/` 下有文件),加载以下数据感知已写内容:
bash
for ch in $(seq $((START_CH - 5)) $((START_CH - 1))); do cat "$PROJECT_ROOT/.webnovel/summaries/ch$(printf '%04d' $ch).md" 2>/dev/null done
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \ knowledge query-entity-state --entity "{protagonist_id}" --at-chapter {上一卷最后章}
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \ knowledge query-relationships --entity "{protagonist_id}" --at-chapter {上一卷最后章}
python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" \ memory-contract get-open-loops
**CSV 创作参考**(卷级规划时按需检索):
bash
python -X utf8 "${SCRIPTS_DIR}/reference_search.py" --skill plan --table 爽点与节奏 --query "{卷级核心冲突}" --genre "${GENRE}" python -X utf8 "${SCRIPTS_DIR}/reference_search.py" --skill plan --table 桥段套路 --query "{卷级核心冲突}" --genre "${GENRE}"
按需读取(保持不变):
设定集/世界观.md设定集/力量体系.md设定集/主角卡.md设定集/反派设计.md.webnovel/idea_bank.json
[ ] Step 2: 在 plan Step 6(卷纲骨架)加入已写状态参照
在 Step 6 的"卷纲必须明确"列表后新增:
跨卷一致性检查:
- 上一卷未回收的伏笔必须出现在新卷的伏笔规划中(继续推进或标记回收)
- 角色关系变化必须延续(不能当上一卷没发生过)
- 主角能力/境界必须承接(不能回退也不能跳级,除非有剧情解释)
[ ] Step 3: Commit
git add webnovel-writer/skills/webnovel-plan/SKILL.md
git commit -m "feat: plan reads write history for cross-volume awareness"
Files: (read-only verification)
[ ] Step 1: 运行全量 prompt integrity 测试
cd "D:\wk\novel skill\webnovel-writer\webnovel-writer" && python -m pytest scripts/data_modules/tests/test_prompt_integrity.py -v --tb=short
[ ] Step 2: 运行 CSV 配置对齐测试
cd "D:\wk\novel skill\webnovel-writer\webnovel-writer" && python -m pytest scripts/data_modules/tests/test_csv_config.py -v --tb=short
[ ] Step 3: 验证裁决表别名覆盖
python3 -c "
import csv
from pathlib import Path
path = Path('webnovel-writer/references/csv/裁决规则.csv')
with open(path, 'r', encoding='utf-8-sig') as f:
for row in csv.DictReader(f):
genre = row['题材']
keywords = row['关键词']
print(f'{genre}: {keywords}')
"
确认"修仙""西幻""系统流""都市脑洞""历史脑洞"等 init 题材名都出现在对应行的关键词中。
模拟检查:
_route() 匹配"修仙" → 路由表 fallback(无精确匹配,但有 explicit_genre_fallback)_load_reasoning("修仙") → 裁决表匹配到"东方仙侠"行(通过别名"修仙")确认这条路径不断裂。
[ ] Step 5: Commit final
git add -A && git commit -m "chore: final verification for chain integrity fixes"