소스 검색

fix: harden timeline constraints across plan/write review flow

lingfengQAQ 3 달 전
부모
커밋
af21db4580

+ 37 - 6
webnovel-writer/agents/consistency-checker.md

@@ -89,16 +89,42 @@ model: inherit
 - Event sequence is chronologically logical
 - Time-sensitive elements (deadlines, age, seasonal events) align
 - Flashbacks are clearly marked
+- Chapter time anchors match volume timeline
+
+**Severity Classification** (时间问题分级):
+| 问题类型 | Severity | 说明 |
+|---------|----------|------|
+| 倒计时算术错误 | **critical** | D-5 直接跳到 D-2,必须修复 |
+| 事件先后矛盾 | **high** | 先发生的事情后写,逻辑混乱 |
+| 年龄/修炼时长冲突 | **high** | 算术错误,如15岁修炼5年却10岁入门 |
+| 时间回跳无标注 | **high** | 非闪回章节却出现时间倒退 |
+| 大跨度无过渡 | **high** | 跨度>3天却无过渡说明 |
+| 时间锚点缺失 | **medium** | 无法确定章节时间,但不影响逻辑 |
+| 轻微时间模糊 | **low** | 时段不明确但不影响剧情 |
+
+> 输出 JSON 时,`issues[].severity` 必须使用小写枚举:`critical|high|medium|low`。
 
 **Red Flags** (TIMELINE_ISSUE):
 ```
-❌ 第10章提到"三天后的宗门大比",第11章描述大比结束(中间无时间流逝)
+❌ [critical] 第10章物资耗尽倒计时 D-5,第11章直接变成 D-2(跳过3天)
+   → Setup: D-5 | Next chapter: D-2 | Missing: 3 days
+   → VIOLATION: Countdown arithmetic error (MUST FIX)
+
+❌ [high] 第10章提到"三天后的宗门大比",第11章描述大比结束(中间无时间流逝)
    → Setup: 3 days until event | Next chapter: Event concluded
    → VIOLATION: Missing time passage
 
-❌ 主角15岁修炼5年,推算应该10岁开始,但设定集记录"12岁入门"
+❌ [high] 主角15岁修炼5年,推算应该10岁开始,但设定集记录"12岁入门"
    → Age: 15 | Cultivation years: 5 | Start age: 10 | Record: 12
    → VIOLATION: Timeline arithmetic error
+
+❌ [high] 第一章末世降临,第二章就建立帮派(无时间过渡)
+   → Chapter 1: 末世第1天 | Chapter 2: 建帮派火拼
+   → VIOLATION: Major event without reasonable time progression
+
+❌ [high] 本章时间锚点"末世第3天",上章是"末世第5天"(时间回跳)
+   → Previous: 末世第5天 | Current: 末世第3天
+   → VIOLATION: Time regression without flashback marker
 ```
 
 ### Step 3: Entity Consistency Check
@@ -127,23 +153,25 @@ Chapters {N} - {M}
 | Chapter | Issue | Severity | Details |
 |---------|-------|----------|---------|
 | {N} | ✓ No violations | - | - |
-| {M} | ✗ POWER_CONFLICT | High | 主角筑基3层使用金丹期技能"破空斩" |
+| {M} | ✗ POWER_CONFLICT | high | 主角筑基3层使用金丹期技能"破空斩" |
 
 **Verdict**: {X} violations found
 
 ## 地点/角色一致性 (Location & Character)
 | Chapter | Type | Issue | Severity |
 |---------|------|-------|----------|
-| {M} | Location | ✗ LOCATION_ERROR | Medium | 未描述移动过程,从天云宗跳跃到血煞秘境 |
+| {M} | Location | ✗ LOCATION_ERROR | medium | 未描述移动过程,从天云宗跳跃到血煞秘境 |
 
 **Verdict**: {Y} violations found
 
 ## 时间线一致性 (Timeline)
 | Chapter | Issue | Severity | Details |
 |---------|-------|----------|---------|
-| {M} | ✗ TIMELINE_ISSUE | Low | 大比倒计时逻辑不一致 |
+| {M} | ✗ TIMELINE_ISSUE | critical | 倒计时从 D-5 跳到 D-2 |
+| {M} | ✗ TIMELINE_ISSUE | high | 大比倒计时逻辑不一致 |
 
 **Verdict**: {Z} violations found
+**Critical Timeline Issues**: {count} (MUST FIX before continuing)
 
 ## 新实体一致性检查 (Entity Consistency)
 - ✓ All new entities consistent with world-building: {count}
@@ -193,10 +221,13 @@ python "${SCRIPTS_DIR}/webnovel.py" --project-root "{PROJECT_ROOT}" index mark-i
 ❌ Approving chapters with POWER_CONFLICT (战力崩坏)
 ❌ Ignoring untagged new entities
 ❌ Accepting teleportation without in-world explanation
+❌ **Downgrading TIMELINE_ISSUE severity** (时间问题不得降级)
+❌ **Approving critical/high timeline issues without fix** (严重时间问题必须修复)
 
 ## Success Criteria
 
-- 0 critical violations (power conflicts, unexplained character changes)
+- 0 critical violations (power conflicts, unexplained character changes, **timeline arithmetic errors**)
+- 0 high-severity timeline issues (**countdown errors, time regression, major events without time progression**)
 - All new entities consistent with existing world-building
 - Location and timeline transitions are logical
 - Report provides specific fix recommendations for polish step

+ 50 - 9
webnovel-writer/agents/context-agent.md

@@ -32,11 +32,12 @@ model: inherit
 
 输出必须是单一执行包,包含 3 层:
 
-1. **任务书(7板块)**
+1. **任务书(8板块)**
 - 本章核心任务(目标/阻力/代价、冲突一句话、必须完成、绝对不能、反派层级)
 - 接住上章(上章钩子、读者期待、开头建议)
 - 出场角色(状态、动机、情绪底色、说话风格、红线)
 - 场景与力量约束(地点、可用能力、禁用能力)
+- **时间约束(新增)**(上章时间锚点、本章时间锚点、允许推进跨度、时间过渡要求、倒计时状态)
 - 风格指导(本章类型、参考样本、最近模式、本章建议)
 - 连续性与伏笔(时间/位置/情绪连贯;必须处理/可选伏笔)
 - 追读力策略(未闭合问题 + 钩子类型/强度、微兑现建议、差异化提示)
@@ -74,8 +75,8 @@ model: inherit
 - 若 `chapter_meta` 不存在(如第1章),跳过“接住上章”
 - 最近3章数据不完整时,只用现有数据做差异化检查
 - 若 `plot_threads.foreshadowing` 缺失或非列表:
-  - 视为“当前无结构化伏笔数据”,第 6 板块输出空清单并显式标注“数据缺失,需人工补录”
-  - 禁止静默跳过第 6 板块
+  - 视为“当前无结构化伏笔数据”,第 7 板块输出空清单并显式标注“数据缺失,需人工补录”
+  - 禁止静默跳过第 7 板块
 
 **章节编号规则**: 4位数字,如 `0001`, `0099`, `0100`
 
@@ -130,6 +131,43 @@ python "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" extract-cont
 - 推荐读取:`reader_signal` 与 `genre_profile.reference_hints`
 - 条件读取:`rag_assist`(当 `invoked=true` 且 `hits` 非空时,必须提炼成可执行约束,禁止只贴检索命中)
 
+### Step 0.6: 时间线读取(新增,必做)
+
+先确定 `{volume_id}`:
+- 优先读取 `state.json` 中当前卷信息(如有)
+- 若缺失,则从 `大纲/总纲.md` 的章节范围反推 `{NNNN}` 所在卷
+
+读取本卷时间线表:
+```bash
+cat "{project_root}/大纲/第{volume_id}卷-时间线.md"
+```
+
+从章纲提取本章时间字段:
+- `时间锚点`:本章发生的具体时间
+- `章内时间跨度`:本章覆盖的时间长度
+- `与上章时间差`:与上章的时间间隔
+- `倒计时状态`:若有倒计时事件的推进情况
+
+从上章 chapter_meta 或章纲提取:
+- 上章结束时间锚点
+- 上章倒计时状态
+
+生成时间约束输出(必须包含在任务书第 5 板块):
+```markdown
+## 时间约束
+- 上章时间锚点: {末世第3天 黄昏}
+- 本章时间锚点: {末世第4天 清晨}
+- 与上章时间差: {跨夜}
+- 本章允许推进: 最大 {章内时间跨度}
+- 时间过渡要求: {若跨夜/跨日,需补写的过渡句}
+- 倒计时状态: {物资耗尽 D-5 → D-4 / 无}
+```
+
+**时间约束硬规则**:
+- 若 `与上章时间差` 为"跨夜"或"跨日",必须在任务书中标注"需补写时间过渡"
+- 若存在倒计时事件,必须校验推进是否正确(D-N 只能变为 D-(N-1),不可跳跃)
+- 时间锚点不得回跳(除非明确标注为闪回章节)
+
 ### Step 1: 读取大纲与状态
 - 大纲:`大纲/卷N/第XXX章.md` 或 `大纲/第{卷}卷-详细大纲.md`
   - 必须优先提取并写入任务书:目标/阻力/代价/反派层级/本章变化/章末未闭合问题/钩子(若存在)
@@ -167,7 +205,7 @@ python "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index recent
   - `remaining = target_chapter - current_chapter`(若缺失则记为 `null`)
   - 二次排序:`planted_chapter` 升序(更早埋设优先)
   - 三次排序:`content` 字典序(确保稳定)
-- 输出到第 6 板块时,按 `remaining` 升序列出。
+- 输出到第 7 板块时,按 `remaining` 升序列出。
 
 ### Step 4: 摘要与推断补全
 - 优先读取 `.webnovel/summaries/ch{NNNN-1}.md`
@@ -180,10 +218,10 @@ python "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index recent
 ### Step 5: 组装创作执行包(任务书 + Contract v2 + 直写提示词)
 输出可直接供 Step 2A 消费的单一执行包,不拆分独立 Step 1.5。
 
-- 第 6 板块必须包含“伏笔优先级清单”:
+- 第 7 板块必须包含“伏笔优先级清单”:
   - `必须处理(本章优先)`:`remaining <= 5` 或已超期(`remaining < 0`),全部列出不截断
   - `可选伏笔(可延后)`:最多 5 条
-- 第 6 板块生成规则(统一口径):
+- 第 7 板块生成规则(统一口径):
   - 仅纳入未回收伏笔(见 Step 3 回收判定)
   - 主排序按 `remaining` 升序,`remaining=null` 放末尾
   - 若 `必须处理` 超过 3 条:前 3 条标记“最高优先”,其余标记“本章仍需处理”
@@ -205,10 +243,11 @@ Contract v2 必须字段(不可缺):
 - 红线3:能力或信息无因果来源(突然会/突然知道)
 - 红线4:角色动机断裂(行为与近期目标明显冲突且无触发)
 - 红线5:合同与任务书冲突(例如“过渡章=true”却要求高强度高潮兑现)
+- **红线6:时间逻辑错误**(时间回跳、倒计时跳跃、大跨度无过渡)
 
 通过标准:
 - 红线 fail 数 = 0
-- 执行包内包含“不可变事实清单 + 章节节拍 + 终检清单”
+- 执行包内包含“不可变事实清单 + 章节节拍 + 终检清单 + 时间约束
 - Step 2A 在不补问情况下可直接起草正文
 
 ---
@@ -216,12 +255,14 @@ Contract v2 必须字段(不可缺):
 ## 成功标准
 
 1. ✅ 创作执行包可直接驱动 Step 2A(无需补问)
-2. ✅ 任务书包含 7 个板块
+2. ✅ 任务书包含 8 个板块(含时间约束)
 3. ✅ 上章钩子与读者期待明确(若存在)
 4. ✅ 角色动机/情绪为推断结果(非空)
 5. ✅ 最近模式已对比,给出差异化建议
 6. ✅ 章末钩子建议类型明确
 7. ✅ 反派层级已注明(若大纲提供)
-8. ✅ 第 6 板块已基于 `plot_threads.foreshadowing` 按紧急度排序输出
+8. ✅ 第 7 板块已基于 `plot_threads.foreshadowing` 按紧急度排序输出
 9. ✅ Contract v2 字段完整且与任务书一致
 10. ✅ 逻辑红线校验通过(fail=0)
+11. ✅ **时间约束板块完整**(上章时间锚点、本章时间锚点、允许推进跨度、过渡要求、倒计时状态)
+12. ✅ **时间逻辑红线通过**(无回跳、无倒计时跳跃、大跨度有过渡要求)

+ 62 - 3
webnovel-writer/skills/webnovel-plan/SKILL.md

@@ -34,6 +34,7 @@ export PROJECT_ROOT="$(python "${SCRIPTS_DIR}/webnovel.py" --project-root "${WOR
 ## References(按步骤导航)
 
 - Step 3(必读,节拍表模板):[大纲-卷节拍表.md](../../templates/output/大纲-卷节拍表.md)
+- Step 4.5(必读,时间线模板):[大纲-卷时间线.md](../../templates/output/大纲-卷时间线.md)
 - Step 4(必读,题材配置):[genre-profiles.md](../../references/genre-profiles.md)
 - Step 4(必读,Strand 节奏):[strand-weave-pattern.md](../../references/shared/strand-weave-pattern.md)
 - Step 4(可选,爽点结构需要细化):[cool-points-guide.md](../../references/shared/cool-points-guide.md)
@@ -55,6 +56,7 @@ Use progressive disclosure and load only what current step requires:
 2. Build setting baseline from 总纲 + 世界观 (in-place incremental).
 3. Select volume and confirm scope.
 4. Generate volume beat sheet (节拍表).
+4.5. Generate volume timeline (时间线表).
 5. Generate volume skeleton.
 6. Generate chapter outlines in batches.
 7. Enrich existing setting files from volume outline (in-place incremental).
@@ -127,6 +129,32 @@ Completion criteria:
 - `大纲/第{volume_id}卷-节拍表.md` 存在且非空
 - Step 4/5 能直接引用 Catalyst / 中段反转 / 最低谷 / 大兑现 / 新钩子来锚定节奏
 
+## 4.5) Generate volume timeline (时间线表)
+
+目标:为本卷建立时间轴基准,确保章节间时间推进逻辑自洽,避免"第一章灾变第二章火拼"的时间跳跃问题。
+
+Load template:
+```bash
+cat "${SKILL_ROOT}/../../templates/output/大纲-卷时间线.md"
+```
+
+Must satisfy (hard requirements):
+- **时间基准(必填)**:明确本卷使用的时间体系(末世第X天/仙历年月/现代日期)
+- **本卷时间跨度(必填)**:本卷覆盖的时间范围
+- **关键倒计时事件**:若有时限性事件(物资耗尽/大比开始/截止日期),必须列出并标注 D-N
+
+Write output:
+```bash
+@'
+{timeline_content}
+'@ | Set-Content -Encoding UTF8 "$PROJECT_ROOT/大纲/第{volume_id}卷-时间线.md"
+```
+
+Completion criteria:
+- `大纲/第{volume_id}卷-时间线.md` 存在且非空
+- 时间基准和本卷跨度已明确
+- 若存在倒计时事件,已在表中列出
+
 ## 5) Generate volume skeleton
 Load genre profile and apply standards:
 ```bash
@@ -294,6 +322,10 @@ Chapter format (include 反派层级 for context-agent):
 - 目标: {20字以内}
 - 阻力: {20字以内}
 - 代价: {20字以内}
+- 时间锚点: {末世第X天 时段/仙历X年X月X日/具体日期+时段}
+- 章内时间跨度: {如 3小时/半天/1天}
+- 与上章时间差: {如 紧接/6小时/1天/跨夜}
+- 倒计时状态: {事件A D-3 -> D-2 / 无}
 - 爽点: {类型} - {30字以内}
 - Strand: {Quest|Fire|Constellation}
 - 反派层级: {无/小/中/大}
@@ -304,6 +336,15 @@ Chapter format (include 反派层级 for context-agent):
 - 钩子: {类型} - {30字以内}
 ```
 
+**时间字段说明**:
+- **时间锚点**:本章发生的具体时间点,必须与时间线表一致
+- **章内时间跨度**:本章内容覆盖的时间长度
+- **与上章时间差**:与上一章结束时间的间隔
+  - 紧接:无时间间隔,直接承接
+  - 跨夜:过夜但不超过 12 小时
+  - 具体时长:如 6小时、1天、3天
+- **倒计时状态**:若存在倒计时事件,标注推进情况(D-N → D-(N-1))
+
 **字段说明**:
 - **章末未闭合问题**:本章结尾必须保留的“未闭合决策/问题”,用于驱动读者点下一章。
   - 规则:必须与 **钩子** 的类型/强度一致;不得出现“钩子很强但问题很虚”的错配。
@@ -370,6 +411,10 @@ Every chapter must have:
 - 目标(20 字以内)
 - 阻力(20 字以内)
 - 代价(20 字以内)
+- 时间锚点(必填)
+- 章内时间跨度(必填)
+- 与上章时间差(必填)
+- 倒计时状态(若有倒计时事件则必填)
 - 爽点(类型 + 30 字描述)
 - Strand(Quest/Fire/Constellation)
 - 反派层级(无/小/中/大)
@@ -379,7 +424,14 @@ Every chapter must have:
 - 章末未闭合问题(30 字以内)
 - 钩子(类型 + 30 字描述)
 
-**6. 设定补全检查(新增)**
+**6. 时间线一致性检查(新增)**
+- 时间线表文件存在:`大纲/第{volume_id}卷-时间线.md`
+- 所有章节时间锚点已填写
+- 时间单调递增(不得回跳,除非明确标注为闪回)
+- 倒计时推进正确(D-5 → D-4 → D-3,不得跳跃)
+- 大跨度时间跳跃(>3天)必须有过渡章说明或明确标注
+
+**7. 设定补全检查**
 - 本卷涉及的新角色/势力/规则已回写到现有设定集文件
 - 所有新增条目可回溯到本卷章纲章节
 - `BLOCKER` 数量为 0;若 >0,必须先裁决,不得进入 state 更新
@@ -393,16 +445,23 @@ python "${SCRIPTS_DIR}/webnovel.py" --project-root "$PROJECT_ROOT" update-state
 
 Final check:
 - 节拍表文件已写入:`大纲/第{volume_id}卷-节拍表.md`
+- 时间线表文件已写入:`大纲/第{volume_id}卷-时间线.md`
 - 章纲文件已写入:`大纲/第{volume_id}卷-详细大纲.md`
 - 设定集已完成基线补齐与本卷增量补充(原文件内可见)
-- 每章包含:目标/阻力/代价/爽点/Strand/反派层级/视角/关键实体/本章变化/章末未闭合问题/钩子
+- 每章包含:目标/阻力/代价/时间锚点/章内时间跨度/与上章时间差/爽点/Strand/反派层级/视角/关键实体/本章变化/章末未闭合问题/钩子
+- 时间线单调递增,倒计时推进正确
 - 与总纲冲突/高潮一致,约束触发频率合理(如有 idea_bank)
 
 ### Hard fail conditions (must stop)
 - 节拍表文件不存在或为空
 - 节拍表中段反转缺失(未按“必填/无(理由)”规则填写)
+- **时间线表文件不存在或为空**
 - 章纲文件不存在或为空
-- 任一章节缺少:目标/阻力/代价/爽点/Strand/反派层级/视角/关键实体/本章变化/章末未闭合问题/钩子
+- 任一章节缺少:目标/阻力/代价/时间锚点/章内时间跨度/与上章时间差/爽点/Strand/反派层级/视角/关键实体/本章变化/章末未闭合问题/钩子
+- **任一章节时间字段(时间锚点/章内时间跨度/与上章时间差)缺失**
+- **时间回跳且未标注为闪回**
+- **倒计时算术冲突(如 D-5 直接跳到 D-2)**
+- **重大事件发生时间与前章间隔不足且无合理解释(如末世第1天建帮派)**
 - 与总纲核心冲突或卷末高潮明显冲突
 - 设定集基线未补齐,或本卷增量未回写到现有设定集
 - 存在 `BLOCKER` 未裁决

+ 31 - 0
webnovel-writer/skills/webnovel-write/references/step-3-review-gate.md

@@ -94,3 +94,34 @@ python "${SCRIPTS_DIR}/webnovel.py" --project-root "${PROJECT_ROOT}" index save-
 - `overall_score` 已生成。
 - `save-review-metrics` 已成功。
 - 审查报告中的 `issues`、`severity_counts` 可被 Step 4 直接消费。
+- **时间线闸门(新增)**:若存在 `TIMELINE_ISSUE` 且 `severity >= high`,禁止进入 Step 4/5,必须先修复。
+
+### 时间线闸门规则
+
+**Hard Block(必须修复才能继续)**:
+- `TIMELINE_ISSUE` + `severity = critical`(倒计时算术错误)
+- `TIMELINE_ISSUE` + `severity = high`(事件先后矛盾/年龄冲突/时间回跳/大跨度无过渡)
+
+**Soft Warning(建议修复但可继续)**:
+- `TIMELINE_ISSUE` + `severity = medium`(时间锚点缺失)
+- `TIMELINE_ISSUE` + `severity = low`(轻微时间模糊)
+
+**闸门判定逻辑**:
+```text
+timeline_issues = filter(issues, type="TIMELINE_ISSUE")
+critical_timeline = filter(timeline_issues, severity in ["critical", "high"])
+
+if len(critical_timeline) > 0:
+    BLOCK: "存在 {len(critical_timeline)} 个严重时间线问题,必须修复后才能进入润色步骤"
+    for issue in critical_timeline:
+        print(f"- 第{issue.chapter}章: {issue.description}")
+    return BLOCKED
+else:
+    PASS: "时间线检查通过"
+```
+
+**修复指引**:
+- 倒计时错误 → 修正倒计时推进,确保 D-N → D-(N-1) 连续
+- 时间回跳 → 添加闪回标记,或调整时间锚点
+- 大跨度无过渡 → 添加时间过渡句/段,或插入过渡章
+- 事件先后矛盾 → 调整事件发生顺序或添加时间跳跃说明

+ 51 - 0
webnovel-writer/templates/output/大纲-卷时间线.md

@@ -0,0 +1,51 @@
+# 第 {volume_id} 卷 时间线表
+
+> 本表为本卷时间轴的单一事实源,章纲时间字段必须与本表一致。
+
+## 卷级时间设定
+
+| 项目 | 值 |
+|------|-----|
+| 时间基准 | {如:末世第1天 / 仙历3021年春 / 现代2026年3月} |
+| 本卷时间跨度 | {如:末世第1-30天 / 约1个月} |
+| 关键倒计时事件 | {如:物资耗尽 D-7 / 宗门大比 D-10 / 无} |
+
+## 章节时间轴
+
+| 章节 | 时间锚点 | 章内跨度 | 与上章间隔 | 倒计时状态 | 备注 |
+|------|---------|---------|-----------|-----------|------|
+| 第1章 | {末世第1天 清晨} | {4小时} | {-} | {物资耗尽 D-7} | {开篇} |
+| 第2章 | {末世第1天 中午} | {3小时} | {0(紧接)} | {D-7} | {} |
+| 第3章 | {末世第1天 傍晚} | {2小时} | {2小时} | {D-7} | {} |
+| 第4章 | {末世第2天 清晨} | {6小时} | {跨夜} | {D-6} | {需交代夜间} |
+| ... | ... | ... | ... | ... | ... |
+
+## 时间跳跃规则
+
+### 允许的时间推进
+- 同日内连续:无需特殊交代
+- 跨夜(6-12小时):需 1-2 句过渡(如"一夜无话"/"休整一晚")
+- 跨日(1-3天):需过渡段落或过渡章说明期间发生的事
+- 大跨度(>3天):必须有过渡章,或明确的时间标记("三天后")
+
+### 禁止的时间操作
+- ❌ 时间回跳(除非是明确的回忆/闪回)
+- ❌ 倒计时跳跃(D-5 不能直接跳到 D-2)
+- ❌ 无交代的大跨度推进
+
+## 倒计时事件追踪
+
+| 事件名称 | 起始 | 当前状态 | 触发章节 | 结果 |
+|---------|------|---------|---------|------|
+| {物资耗尽} | {D-7} | {进行中/已触发/已化解} | {第N章} | {} |
+| {宗门大比} | {D-10} | {} | {} | {} |
+
+## 验证清单
+
+在完成本卷章纲后,检查以下项目:
+
+- [ ] 所有章节时间锚点已填写
+- [ ] 时间单调递增(无回跳)
+- [ ] 跨夜/跨日章节有过渡说明
+- [ ] 倒计时推进正确(每过一日 D-N → D-(N-1))
+- [ ] 大跨度跳跃有合理解释