dsh-novel-write-engine 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,51 @@ export interface SummaryDto {
35
35
  };
36
36
  /** True only when the book target is reached; done alone means the chapter is archived. */
37
37
  finished?: boolean;
38
+ book?: {
39
+ premise: string;
40
+ logline: string;
41
+ strict: boolean;
42
+ target: number | null;
43
+ outline: {
44
+ present: boolean;
45
+ total: number;
46
+ planned: number;
47
+ archived: number;
48
+ coverage: number;
49
+ volumes: Array<{
50
+ title: string;
51
+ start: number;
52
+ end: number;
53
+ planned: number;
54
+ archived: number;
55
+ }>;
56
+ };
57
+ worldbook: {
58
+ present: boolean;
59
+ characters: number;
60
+ locations: number;
61
+ factions: number;
62
+ rules: number;
63
+ glossary: number;
64
+ backstory: number;
65
+ };
66
+ };
67
+ quality?: {
68
+ averageScore: number;
69
+ scores: number[];
70
+ trend: number;
71
+ };
72
+ health?: {
73
+ ok: boolean;
74
+ blocking: number;
75
+ stateErrors: number;
76
+ };
77
+ activity?: Array<{
78
+ at: string;
79
+ op: string;
80
+ chapter: number;
81
+ status: string;
82
+ }>;
38
83
  }
39
84
  export interface ChapterRowDto {
40
85
  num: number;
@@ -44,6 +44,46 @@ export interface PanelView {
44
44
  averageScore: number;
45
45
  blocking: number;
46
46
  };
47
+ book: {
48
+ present: boolean;
49
+ strict: boolean;
50
+ premise: string;
51
+ target: number | null;
52
+ planned: number;
53
+ outlineTotal: number;
54
+ archivedCards: number;
55
+ coverage: number;
56
+ volumes: Array<{
57
+ title: string;
58
+ range: string;
59
+ planned: number;
60
+ archived: number;
61
+ }>;
62
+ worldbook: {
63
+ characters: number;
64
+ locations: number;
65
+ factions: number;
66
+ rules: number;
67
+ glossary: number;
68
+ backstory: number;
69
+ };
70
+ };
71
+ quality: {
72
+ averageScore: number;
73
+ scores: number[];
74
+ trend: number;
75
+ };
76
+ health: {
77
+ ok: boolean;
78
+ blocking: number;
79
+ stateErrors: number;
80
+ };
81
+ activity: Array<{
82
+ at: string;
83
+ op: string;
84
+ chapter: number;
85
+ status: string;
86
+ }>;
47
87
  nextTitle: string;
48
88
  nextDetail: string;
49
89
  nextTool: string;
@@ -52,7 +92,7 @@ export interface PanelView {
52
92
  revision: string;
53
93
  next: string;
54
94
  }
55
- export declare const PANEL_SCHEMA_VERSION = 1;
95
+ export declare const PANEL_SCHEMA_VERSION = 2;
56
96
  /**
57
97
  * Project the wire payload into strings. Version mismatch wins over everything
58
98
  * else: a stale panel must never render data from another schema as if it were
@@ -4,11 +4,13 @@ export declare const PLUGIN_NAME = "dsh-novel-write-engine";
4
4
  export declare const PANEL_ID = "novel-workshop";
5
5
  export declare const PANEL_ROUTE = "/api/novel-write-engine/panel";
6
6
  export declare const SKILL_NAME = "novel-write-engine";
7
- export declare const REMOTE_VERSION = 1;
7
+ export declare const REMOTE_VERSION = 2;
8
8
  /** The panel is a recent-history view; the wire payload and UI use one cap. */
9
9
  export declare const PANEL_CHAPTER_LIMIT = 30;
10
10
  /** Project-relative locations. Every write goes through these constants. */
11
11
  export declare const PROJECT_FILE = "novel.yaml";
12
+ export declare const OUTLINE_FILE = "outline/outline.yaml";
13
+ export declare const WORLDBOOK_FILE = "outline/worldbook.yaml";
12
14
  export declare const STATE_DIR = "state";
13
15
  export declare const CHAPTERS_DIR = "chapters";
14
16
  export declare const PLAN_DIR = "plans";
@@ -57,6 +59,14 @@ export declare const LIMITS: {
57
59
  maxWorldPlanObjectiveChars: number;
58
60
  /** Cast plus summary may exceed eight, but not without a bound. */
59
61
  maxActiveCast: number;
62
+ /** Outline and worldbook are protected context, so they need hard bounds. */
63
+ maxOutlineChapters: number;
64
+ maxOutlineVolumes: number;
65
+ maxOutlineTextFieldChars: number;
66
+ maxOutlineNotesChars: number;
67
+ maxWorldbookEntries: number;
68
+ maxWorldbookTextChars: number;
69
+ maxSearchQueryChars: number;
60
70
  };
61
71
  /** Re-exported enums make adapter code readable without importing types twice. */
62
72
  export declare const SCENE_TYPE_DEFAULT: SceneType;
@@ -66,7 +76,7 @@ export declare const INITIAL_STAGE: Stage;
66
76
  /** The order used to render the nine-phase progress strip. */
67
77
  export declare const PHASE_STRIP: readonly ["P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P9"];
68
78
  /** Tool names, kept here so the arch test can assert one namespace. */
69
- export declare const TOOL_NAMES: readonly ["novel_init", "novel_status", "novel_brief", "novel_plan_world", "novel_plan_chapter", "novel_write_draft", "novel_review", "novel_revise", "novel_check", "novel_archive", "novel_word_count", "novel_state", "novel_amend", "novel_rollback", "novel_diff", "novel_export", "novel_audit", "novel_pipeline"];
79
+ export declare const TOOL_NAMES: readonly ["novel_init", "novel_status", "novel_brief", "novel_plan_world", "novel_plan_chapter", "novel_write_draft", "novel_review", "novel_revise", "novel_check", "novel_archive", "novel_word_count", "novel_state", "novel_amend", "novel_rollback", "novel_diff", "novel_export", "novel_audit", "novel_pipeline", "novel_blueprint", "novel_outline", "novel_outline_import", "novel_worldbook", "novel_search", "novel_doctor", "novel_report", "novel_guide", "novel_reopen"];
70
80
  export type ToolName = (typeof TOOL_NAMES)[number];
71
- /** The eight high-frequency tools kept when `tools.mode = core`. */
81
+ /** The ten high-frequency tools kept when `tools.mode = core`. */
72
82
  export declare const CORE_TOOLS: readonly ToolName[];
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Chinese one-line explanation for the tool each engine state recommends.
3
+ * Shared by the panel and slash commands so both surfaces speak the same
4
+ * language; unknown tools fall back to the engine's own reason.
5
+ */
6
+ export declare const NEXT_DETAILS: Record<string, string>;
@@ -20,8 +20,8 @@ export declare const SCENE_TYPES: readonly ["战斗/动作章", "日常过渡章
20
20
  export type SceneType = (typeof SCENE_TYPES)[number];
21
21
  /** A violation is blocking unless the rule pack declares it advisory. */
22
22
  export type Severity = 'blocker' | 'advisory';
23
- /** All twenty-two service operations. */
24
- export declare const OPERATIONS: readonly ["initProject", "archiveChapter", "amend", "rollback", "submitWorldPlan", "submitChapterPlan", "submitDraft", "submitReview", "submitRevision", "runCheck", "getStatus", "getBrief", "countWords", "queryState", "diff", "auditHistory", "advise", "export", "panelSummary", "panelChapters", "panelGates", "stats"];
23
+ /** All thirty-one service operations (22 inherited from 0.1.x, 9 book-level). */
24
+ export declare const OPERATIONS: readonly ["initProject", "archiveChapter", "amend", "rollback", "reopenChapter", "submitWorldPlan", "submitChapterPlan", "submitDraft", "submitReview", "submitRevision", "runCheck", "submitBookPlan", "submitOutline", "importOutline", "submitWorldbook", "getStatus", "getBrief", "countWords", "queryState", "diff", "auditHistory", "advise", "search", "doctor", "report", "guide", "export", "panelSummary", "panelChapters", "panelGates", "stats"];
25
25
  export type Operation = (typeof OPERATIONS)[number];
26
26
  /** Structured, non-fatal note attached to a successful result. */
27
27
  export interface Warning {
@@ -70,6 +70,8 @@ export declare const ERROR_CODES: {
70
70
  readonly PATH_ESCAPE: "ENGINE_PATH_ESCAPE";
71
71
  readonly LOCK_TIMEOUT: "ENGINE_LOCK_TIMEOUT";
72
72
  readonly TXN_ABORTED: "ENGINE_TXN_ABORTED";
73
+ readonly JOURNAL_MISSING: "ENGINE_JOURNAL_MISSING";
74
+ readonly TXN_IN_PROGRESS: "ENGINE_TXN_IN_PROGRESS";
73
75
  readonly RULEPACK_INVALID: "ENGINE_RULEPACK_INVALID";
74
76
  readonly ID_EXHAUSTED: "ENGINE_ID_EXHAUSTED";
75
77
  readonly CONFIG_INVALID: "ENGINE_CONFIG_INVALID";
@@ -172,7 +174,7 @@ export interface CheckDocument {
172
174
  verdict: 'pass' | 'fail';
173
175
  }
174
176
  /** Every persisted document whose damage status/panel can report. */
175
- export type StateErrorCode = 'PROJECT_UNREADABLE' | 'PLAN_UNREADABLE' | 'WORLD_PLAN_UNREADABLE' | 'REVIEW_UNREADABLE' | 'CHECK_UNREADABLE' | 'CHAPTERS_UNREADABLE' | 'CHARACTERS_UNREADABLE' | 'WORLD_UNREADABLE' | 'LOCKS_UNREADABLE' | 'TIMELINE_UNREADABLE' | 'FORESHADOWS_UNREADABLE' | 'RELATIONSHIPS_UNREADABLE' | 'HANDOFF_UNREADABLE';
177
+ export type StateErrorCode = 'PROJECT_UNREADABLE' | 'PLAN_UNREADABLE' | 'WORLD_PLAN_UNREADABLE' | 'REVIEW_UNREADABLE' | 'CHECK_UNREADABLE' | 'CHAPTERS_UNREADABLE' | 'CHARACTERS_UNREADABLE' | 'WORLD_UNREADABLE' | 'LOCKS_UNREADABLE' | 'TIMELINE_UNREADABLE' | 'FORESHADOWS_UNREADABLE' | 'RELATIONSHIPS_UNREADABLE' | 'HANDOFF_UNREADABLE' | 'OUTLINE_UNREADABLE' | 'WORLDBOOK_UNREADABLE';
176
178
  /** A state document that exists but cannot be read safely. */
177
179
  export interface StateError {
178
180
  path: string;
@@ -526,6 +528,265 @@ export interface ChapterPlanInput {
526
528
  /** Optional in 0.1.3: older plans remain readable; new plans may name 1–8 actors. */
527
529
  cast?: ChapterCastMember[];
528
530
  }
531
+ /** Book-level pitch and structure, persisted in `outline/outline.yaml`. */
532
+ export interface BookPlan {
533
+ premise: string;
534
+ logline: string;
535
+ themes: string[];
536
+ tone: string;
537
+ pov: string;
538
+ audience: string;
539
+ selling_points: string[];
540
+ ending: string;
541
+ /** Strict mode requires a chapter card before P2/P3 for every chapter. */
542
+ strict: boolean;
543
+ /** True once the author explicitly chose strict on/off; used for the first-outline default. */
544
+ strict_explicit?: boolean;
545
+ }
546
+ /** One volume of the planned book. `end_chapter` is inclusive. */
547
+ export interface OutlineVolume {
548
+ id: string;
549
+ title: string;
550
+ start_chapter: number;
551
+ end_chapter: number;
552
+ goal: string;
553
+ arc: string;
554
+ climax: string;
555
+ status: 'planned' | 'writing' | 'done';
556
+ }
557
+ /** One planned chapter card. Only the archive transaction may write the archived fields. */
558
+ export interface OutlineChapter {
559
+ num: number;
560
+ volume: number | null;
561
+ title: string;
562
+ scene_type: SceneType;
563
+ goal: string;
564
+ conflict: string;
565
+ hook: string;
566
+ cast: string[];
567
+ target_words: [number, number];
568
+ notes: string;
569
+ status: 'planned' | 'archived';
570
+ archived_at: string | null;
571
+ word_count: number | null;
572
+ score: number | null;
573
+ }
574
+ /** The planning SSOT read by P1–P8, PG-13, report, doctor and export. */
575
+ export interface OutlineDocument {
576
+ schema_version: 1;
577
+ updated_at: string;
578
+ book: BookPlan;
579
+ volumes: OutlineVolume[];
580
+ chapters: OutlineChapter[];
581
+ }
582
+ /** One worldbuilding rule/constraint. */
583
+ export interface WorldbookRule {
584
+ name: string;
585
+ description: string;
586
+ }
587
+ /** One faction in the world bible. */
588
+ export interface WorldbookFaction {
589
+ name: string;
590
+ description: string;
591
+ goal: string;
592
+ }
593
+ /** One location in the world bible. */
594
+ export interface WorldbookLocation {
595
+ name: string;
596
+ description: string;
597
+ layout: string;
598
+ capacity: number;
599
+ }
600
+ /** One planned character (not the post-prose ledger entry). */
601
+ export interface WorldbookCharacter {
602
+ name: string;
603
+ role: string;
604
+ description: string;
605
+ arc: string;
606
+ }
607
+ /** One glossary entry. */
608
+ export interface WorldbookGlossary {
609
+ term: string;
610
+ definition: string;
611
+ }
612
+ /** One backstory event. */
613
+ export interface WorldbookBackstory {
614
+ time: string;
615
+ event: string;
616
+ }
617
+ /** Worldbuilding plan, persisted in `outline/worldbook.yaml`. */
618
+ export interface WorldbookDocument {
619
+ schema_version: 1;
620
+ updated_at: string;
621
+ premise: string;
622
+ setting: string;
623
+ rules: WorldbookRule[];
624
+ factions: WorldbookFaction[];
625
+ locations: WorldbookLocation[];
626
+ characters: WorldbookCharacter[];
627
+ glossary: WorldbookGlossary[];
628
+ backstory: WorldbookBackstory[];
629
+ themes: string[];
630
+ }
631
+ /** One hit from `novel_search`; the scope names the source family. */
632
+ export interface SearchResultItem {
633
+ kind: 'chapters' | 'summaries' | 'outline' | 'worldbook' | 'ledgers';
634
+ chapter?: number;
635
+ title?: string;
636
+ paragraph?: number;
637
+ snippet: string;
638
+ }
639
+ /** Search response; `total` counts every matching segment, `results` is capped by `limit`. */
640
+ export interface SearchReport {
641
+ query: string;
642
+ scope: 'all' | 'chapters' | 'summaries' | 'outline' | 'worldbook' | 'ledgers';
643
+ total: number;
644
+ truncated: boolean;
645
+ results: SearchResultItem[];
646
+ }
647
+ /** One structured health check. */
648
+ export interface DoctorCheck {
649
+ id: string;
650
+ severity: 'ok' | 'info' | 'warning' | 'error';
651
+ title: string;
652
+ detail: string;
653
+ hint?: string;
654
+ }
655
+ /** `novel_doctor` payload; a missing project is reported, never thrown. */
656
+ export interface DoctorReport {
657
+ ok: boolean;
658
+ root: string;
659
+ checks: DoctorCheck[];
660
+ summary: {
661
+ errors: number;
662
+ warnings: number;
663
+ infos: number;
664
+ };
665
+ }
666
+ /** Book-wide quality, outline, cast and pacing aggregates. */
667
+ export interface BookReport {
668
+ progress: {
669
+ archived: number;
670
+ target: number | null;
671
+ words: number;
672
+ average_words: number;
673
+ percent: number;
674
+ remaining_words: number | null;
675
+ };
676
+ outline: {
677
+ present: boolean;
678
+ strict: boolean;
679
+ planned: number;
680
+ archived: number;
681
+ coverage: number;
682
+ volumes: Array<{
683
+ title: string;
684
+ start: number;
685
+ end: number;
686
+ planned: number;
687
+ archived: number;
688
+ }>;
689
+ drift: Array<{
690
+ chapter: number;
691
+ field: string;
692
+ planned: string;
693
+ actual: string;
694
+ }>;
695
+ };
696
+ worldbook: {
697
+ present: boolean;
698
+ characters: number;
699
+ locations: number;
700
+ factions: number;
701
+ rules: number;
702
+ glossary: number;
703
+ backstory: number;
704
+ };
705
+ quality: {
706
+ average: number;
707
+ median: number;
708
+ min: number;
709
+ max: number;
710
+ last_five: number[];
711
+ trend: number;
712
+ dimensions: Array<{
713
+ id: string;
714
+ average: number;
715
+ samples: number;
716
+ }>;
717
+ };
718
+ pacing: {
719
+ scene_types: Record<string, number>;
720
+ hook_strength: Record<string, number>;
721
+ plot_advancement: Record<string, number>;
722
+ longest: {
723
+ chapter: number;
724
+ words: number;
725
+ } | null;
726
+ shortest: {
727
+ chapter: number;
728
+ words: number;
729
+ } | null;
730
+ };
731
+ cast: {
732
+ total: number;
733
+ top: Array<{
734
+ name: string;
735
+ appearances: number;
736
+ last_seen: number;
737
+ role: string;
738
+ }>;
739
+ };
740
+ foreshadows: {
741
+ open: number;
742
+ dormant: number;
743
+ overdue: number;
744
+ resolved: number;
745
+ oldest: Array<{
746
+ id: string;
747
+ title: string;
748
+ last_touched: number;
749
+ age: number;
750
+ }>;
751
+ };
752
+ timeline: {
753
+ events: number;
754
+ first_chapter: number | null;
755
+ last_chapter: number | null;
756
+ };
757
+ relationships: {
758
+ total: number;
759
+ types: Record<string, number>;
760
+ };
761
+ activity: Array<{
762
+ at: string;
763
+ op: string;
764
+ chapter: number;
765
+ status: string;
766
+ }>;
767
+ warnings: string[];
768
+ }
769
+ /** One onboarding step. */
770
+ export interface GuideStep {
771
+ id: string;
772
+ title: string;
773
+ detail: string;
774
+ done: boolean;
775
+ tool?: string;
776
+ }
777
+ /** `novel_guide` payload. */
778
+ export interface GuideReport {
779
+ state: 'no-project' | 'new' | 'planning' | 'writing' | 'blocked' | 'finished';
780
+ title: string;
781
+ steps: GuideStep[];
782
+ next: {
783
+ tool: string;
784
+ args: Record<string, unknown>;
785
+ reason: string;
786
+ };
787
+ commands: string[];
788
+ tips: string[];
789
+ }
529
790
  /** Draft submission payload. */
530
791
  export interface DraftInput {
531
792
  chapter: number;
@@ -598,6 +859,12 @@ export interface GateInput {
598
859
  /** The three preceding chapters, newest first, for the duplicate rule. */
599
860
  previousTexts: string[];
600
861
  priorSceneTypes: SceneType[];
862
+ /** 0.2.0 planning input; undefined means "no outline" for older fixtures. */
863
+ outline?: OutlineDocument | null;
864
+ /** The chapter plan's target range, used by PG-13. */
865
+ planTargetWords?: [number, number] | null;
866
+ /** The chapter plan's declared cast names, used by PG-13. */
867
+ planCast?: string[] | null;
601
868
  }
602
869
  /** Gate evaluation outcome. */
603
870
  export interface GateResult {
@@ -636,6 +903,30 @@ export interface StatusReport {
636
903
  volume_name?: string;
637
904
  act?: string;
638
905
  act_progress?: string;
906
+ /** 0.2.0 book-level visibility; absent on older synthetic payloads. */
907
+ book?: {
908
+ premise: string;
909
+ logline: string;
910
+ strict: boolean;
911
+ outline: {
912
+ present: boolean;
913
+ total: number;
914
+ planned: number;
915
+ archived: number;
916
+ coverage: number;
917
+ volumes: number;
918
+ current: OutlineChapter | null;
919
+ };
920
+ worldbook: {
921
+ present: boolean;
922
+ characters: number;
923
+ locations: number;
924
+ factions: number;
925
+ rules: number;
926
+ glossary: number;
927
+ backstory: number;
928
+ };
929
+ };
639
930
  next: {
640
931
  tool: string;
641
932
  args: Record<string, unknown>;
@@ -674,5 +965,5 @@ export interface DiffReport {
674
965
  line: string;
675
966
  }>;
676
967
  }
677
- /** Export capabilities. */
678
- export type ExportKind = 'md' | 'txt' | 'epub';
968
+ /** Export capabilities; the last three are book-planning deliverables. */
969
+ export type ExportKind = 'md' | 'txt' | 'epub' | 'outline' | 'worldbook' | 'proposal';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-novel-write-engine",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Novel writing engine for DeepSeek Harness: state machine, gates, rulepacks and ledgers moved from prompts into code.",
5
5
  "keywords": [
6
6
  "dsh-plugin",
@@ -4,7 +4,7 @@
4
4
  config:
5
5
  id: novel-write-engine
6
6
  name: 网文工坊
7
- description: 网文创作专用会话:18 个小说工具全开,无文件写权限,门控与字数由引擎裁决。
7
+ description: 网文创作专用会话:27 个小说工具全开,无文件写权限,门控与字数由引擎裁决。
8
8
  order: 20
9
9
  plugins:
10
10
  - id: persona
package/skills/entry.md CHANGED
@@ -16,6 +16,10 @@ description: 引擎版小说创作流程——状态、门控、字数与写盘
16
16
  5. **不编设定。** 人物、地点、伏笔、资源状态拿不准就 `novel_state` 查。
17
17
  6. **归档是一次事务,且必须核销。** `novel_archive` 必须带 `state_delta`:本章每个角色/伏笔/事件/新设定/关系逐条声明 `created|updated|no_change`;不要手工拼章节索引或交接文件。
18
18
 
19
+ ## 书级规划(0.2.0)
20
+
21
+ 新项目先 `novel_guide`;推荐但不强制:`novel_blueprint`(蓝图/卷)→ `novel_outline`(章卡)→ `novel_worldbook`(设定集)。已有大纲可用 `novel_outline_import` 导入 Markdown/YAML/JSON。只要存在章卡,P2/P3 就按章卡校验标题、场景、字数与 cast;严格模式还要求章卡必须存在。要改已归档章先 `novel_reopen`(必须带 reason)。
22
+
19
23
  ## 流程路由
20
24
 
21
25
  | 当前阶段 | 任务书 | 下一动作 |
@@ -36,7 +40,16 @@ description: 引擎版小说创作流程——状态、门控、字数与写盘
36
40
  | 工具 | 用途 |
37
41
  | --- | --- |
38
42
  | `novel_init` | 建项目 |
39
- | `novel_status` | 当前章/阶段/阻塞/下一步 |
43
+ | `novel_status` | 当前章/阶段/阻塞/书级摘要/下一步 |
44
+ | `novel_blueprint` | 书级蓝图与卷结构 |
45
+ | `novel_outline` | 卷/章卡 |
46
+ | `novel_outline_import` | 导入 Markdown/YAML/JSON 大纲 |
47
+ | `novel_worldbook` | 世界观设定集 |
48
+ | `novel_search` | 搜索正文/大纲/世界观/台账 |
49
+ | `novel_doctor` | 项目体检 |
50
+ | `novel_report` | 全书报告 |
51
+ | `novel_guide` | 上手引导与下一步 |
52
+ | `novel_reopen` | 从归档备份重开紧邻的上一章 |
40
53
  | `novel_brief` | 取阶段任务书与上下文 |
41
54
  | `novel_plan_world` | P1 世界观计划 |
42
55
  | `novel_plan_chapter` | P2 章节计划 |
@@ -50,19 +63,19 @@ description: 引擎版小说创作流程——状态、门控、字数与写盘
50
63
  | `novel_amend` | 受控改状态文档 |
51
64
  | `novel_rollback` | 回退阶段 |
52
65
  | `novel_diff` | 与备份/文本对比 |
53
- | `novel_export` | md/txt/epub |
66
+ | `novel_export` | md/txt/epub/outline/worldbook/proposal |
54
67
  | `novel_audit` | 事务审计 |
55
68
  | `novel_pipeline` | 推荐下一步与参数 |
56
69
 
57
70
  ## 工具怎么用
58
71
 
59
72
  - 参数是 JSON 对象;`summary`、`dimensions`、`issues`、`proof` 是结构化对象,按任务书字段填。
60
- - `novel_check` 必须带四个语义项(`L2-SCENE-ANCHOR` / `L2-CHARACTER-STATE` / `L2-CAUSALITY` / `L2-VOICE`),每项都要有正文逐字引用;缺一项即校验不过。
73
+ - `novel_check` 必须带五个语义项(`L2-SCENE-ANCHOR` / `L2-CHARACTER-STATE` / `L2-CAUSALITY` / `L2-VOICE` / `L2-POV`),每项都要有正文逐字引用,且来自不同句子;缺一项即校验不过。
61
74
  - 失败分三类:参数错(改参数)、门控没过(改正文)、系统故障(查目录/稍后重试)。错误消息里的 code 说明属于哪类。
62
75
  - 门控失败会一次列出**全部**阻塞项;一次改完再交,不要逐条试。
63
76
 
64
77
  ## 交付
65
78
 
66
79
  - 每章归档后,用户在面板「网文工坊」看到章节表与阻塞区。
67
- - 导出:`novel_export md|txt|epub`。
80
+ - 导出:`novel_export md|txt|epub|outline|worldbook|proposal`。
68
81
  - 不要在对话里重复整章正文;工具结果已经可见。