novel-writer-cli 0.0.1
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.
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/agents/chapter-writer.md +142 -0
- package/agents/character-weaver.md +117 -0
- package/agents/consistency-auditor.md +85 -0
- package/agents/plot-architect.md +128 -0
- package/agents/quality-judge.md +232 -0
- package/agents/style-analyzer.md +109 -0
- package/agents/style-refiner.md +97 -0
- package/agents/summarizer.md +128 -0
- package/agents/world-builder.md +161 -0
- package/dist/__tests__/character-voice.test.js +445 -0
- package/dist/__tests__/commit-prototype-pollution.test.js +45 -0
- package/dist/__tests__/engagement.test.js +382 -0
- package/dist/__tests__/foreshadow-visibility.test.js +131 -0
- package/dist/__tests__/hook-ledger.test.js +1028 -0
- package/dist/__tests__/naming-lint.test.js +132 -0
- package/dist/__tests__/narrative-health-injection.test.js +359 -0
- package/dist/__tests__/next-step-prejudge-guardrails.test.js +325 -0
- package/dist/__tests__/next-step-title-fix.test.js +153 -0
- package/dist/__tests__/platform-profile.test.js +274 -0
- package/dist/__tests__/promise-ledger.test.js +189 -0
- package/dist/__tests__/readability-lint.test.js +209 -0
- package/dist/__tests__/text-utils.test.js +39 -0
- package/dist/__tests__/title-policy.test.js +147 -0
- package/dist/advance.js +75 -0
- package/dist/character-voice.js +805 -0
- package/dist/checkpoint.js +126 -0
- package/dist/cli.js +563 -0
- package/dist/cliche-lint.js +515 -0
- package/dist/commit.js +1460 -0
- package/dist/consistency-auditor.js +684 -0
- package/dist/engagement.js +687 -0
- package/dist/errors.js +7 -0
- package/dist/fingerprint.js +16 -0
- package/dist/foreshadow-visibility.js +214 -0
- package/dist/fs-utils.js +68 -0
- package/dist/hook-ledger.js +721 -0
- package/dist/hook-policy.js +107 -0
- package/dist/instruction-gates.js +51 -0
- package/dist/instructions.js +406 -0
- package/dist/latest-summary-loader.js +29 -0
- package/dist/lock.js +121 -0
- package/dist/naming-lint.js +531 -0
- package/dist/ner.js +73 -0
- package/dist/next-step.js +408 -0
- package/dist/novel-ask.js +270 -0
- package/dist/output.js +9 -0
- package/dist/platform-constraints.js +518 -0
- package/dist/platform-profile.js +325 -0
- package/dist/prejudge-guardrails.js +370 -0
- package/dist/project.js +40 -0
- package/dist/promise-ledger.js +723 -0
- package/dist/readability-lint.js +555 -0
- package/dist/safe-parse.js +36 -0
- package/dist/safe-path.js +29 -0
- package/dist/scoring-weights.js +290 -0
- package/dist/steps.js +60 -0
- package/dist/text-utils.js +18 -0
- package/dist/title-policy.js +251 -0
- package/dist/type-guards.js +6 -0
- package/dist/validate.js +131 -0
- package/docs/user/README.md +17 -0
- package/docs/user/guardrails.md +179 -0
- package/docs/user/interactive-gates.md +124 -0
- package/docs/user/novel-cli.md +289 -0
- package/docs/user/ops.md +123 -0
- package/docs/user/quick-start.md +97 -0
- package/docs/user/spec-system.md +166 -0
- package/docs/user/storylines.md +144 -0
- package/package.json +48 -0
- package/schemas/README.md +18 -0
- package/schemas/character-voice-drift.schema.json +135 -0
- package/schemas/character-voice-profiles.schema.json +141 -0
- package/schemas/engagement-metrics.schema.json +38 -0
- package/schemas/hook-ledger.schema.json +108 -0
- package/schemas/platform-profile.schema.json +235 -0
- package/schemas/promise-ledger.schema.json +97 -0
- package/scripts/calibrate-quality-judge.sh +91 -0
- package/scripts/compare-regression-runs.sh +86 -0
- package/scripts/lib/_common.py +131 -0
- package/scripts/lib/calibrate_quality_judge.py +312 -0
- package/scripts/lib/compare_regression_runs.py +142 -0
- package/scripts/lib/run_regression.py +621 -0
- package/scripts/lint-blacklist.sh +201 -0
- package/scripts/lint-cliche.sh +370 -0
- package/scripts/lint-readability.sh +404 -0
- package/scripts/query-foreshadow.sh +252 -0
- package/scripts/run-ner.sh +669 -0
- package/scripts/run-regression.sh +122 -0
- package/skills/cli-step/SKILL.md +158 -0
- package/skills/continue/SKILL.md +348 -0
- package/skills/continue/references/context-contracts.md +169 -0
- package/skills/continue/references/continuity-checks.md +187 -0
- package/skills/continue/references/file-protocols.md +64 -0
- package/skills/continue/references/foreshadowing.md +130 -0
- package/skills/continue/references/gate-decision.md +53 -0
- package/skills/continue/references/periodic-maintenance.md +46 -0
- package/skills/novel-writing/SKILL.md +77 -0
- package/skills/novel-writing/references/quality-rubric.md +140 -0
- package/skills/novel-writing/references/style-guide.md +145 -0
- package/skills/start/SKILL.md +458 -0
- package/skills/start/references/quality-review.md +86 -0
- package/skills/start/references/setting-update.md +44 -0
- package/skills/start/references/vol-planning.md +61 -0
- package/skills/start/references/vol-review.md +58 -0
- package/skills/status/SKILL.md +116 -0
- package/skills/status/references/sample-output.md +60 -0
- package/templates/ai-blacklist.json +79 -0
- package/templates/brief-template.md +46 -0
- package/templates/genre-weight-profiles.json +90 -0
- package/templates/novel-ask/example.answer.json +12 -0
- package/templates/novel-ask/example.question.json +51 -0
- package/templates/platform-profile.json +148 -0
- package/templates/style-profile-template.json +58 -0
- package/templates/web-novel-cliche-lint.json +41 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# 多线叙事指南
|
|
2
|
+
|
|
3
|
+
本系统支持多 POV 群像、势力暗线、跨卷伏笔交汇等复杂叙事结构。
|
|
4
|
+
|
|
5
|
+
## 核心概念
|
|
6
|
+
|
|
7
|
+
### 故事线(Storyline)
|
|
8
|
+
|
|
9
|
+
每条故事线有固定 ID(连字符命名,如 `main-arc`、`faction-war`),一经定义不可重命名。
|
|
10
|
+
|
|
11
|
+
**类型**(`type:` 前缀):
|
|
12
|
+
|
|
13
|
+
| 类型 | 说明 |
|
|
14
|
+
|------|------|
|
|
15
|
+
| `type:main_arc` | 主线,贯穿全书 |
|
|
16
|
+
| `type:faction_conflict` | 势力冲突线 |
|
|
17
|
+
| `type:conspiracy` | 阴谋暗线 |
|
|
18
|
+
| `type:mystery` | 悬疑/谜题线 |
|
|
19
|
+
| `type:character_arc` | 角色成长线 |
|
|
20
|
+
| `type:parallel_timeline` | 平行时间线 |
|
|
21
|
+
|
|
22
|
+
### 卷级角色(Volume Role)
|
|
23
|
+
|
|
24
|
+
每条故事线在每卷中有不同角色:
|
|
25
|
+
|
|
26
|
+
- **primary**:本卷主要推进的线(通常 1-2 条)
|
|
27
|
+
- **secondary**:辅助线,有最小出场频率要求
|
|
28
|
+
- **seasoning**:调味线,偶尔出场,不做频率要求
|
|
29
|
+
|
|
30
|
+
## 快速起步
|
|
31
|
+
|
|
32
|
+
快速起步阶段,系统只初始化 1 条 `type:main_arc` 主线:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"storylines": [
|
|
37
|
+
{
|
|
38
|
+
"id": "main-arc",
|
|
39
|
+
"name": "主线名称",
|
|
40
|
+
"type": "type:main_arc",
|
|
41
|
+
"scope": "novel",
|
|
42
|
+
"status": "active"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
后续在卷规划阶段,PlotArchitect 会根据剧情需要建议新增故事线。
|
|
49
|
+
|
|
50
|
+
## 活跃线限制
|
|
51
|
+
|
|
52
|
+
**同时活跃 ≤4 条**。这是硬约束(LS-002),超出时系统会要求你暂停或合并故事线。
|
|
53
|
+
|
|
54
|
+
为什么限制 4 条?因为每章写作时 ChapterWriter 需要接收所有活跃线的 context,线太多会导致 context 过载和串线风险。
|
|
55
|
+
|
|
56
|
+
## 卷级调度
|
|
57
|
+
|
|
58
|
+
进入卷规划时,PlotArchitect 生成 `storyline-schedule.json`:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"active_storylines": [
|
|
63
|
+
{ "storyline_id": "main-arc", "volume_role": "primary" },
|
|
64
|
+
{ "storyline_id": "faction-war", "volume_role": "secondary" }
|
|
65
|
+
],
|
|
66
|
+
"interleaving_pattern": {
|
|
67
|
+
"secondary_min_appearance": "every_8_chapters"
|
|
68
|
+
},
|
|
69
|
+
"convergence_events": [
|
|
70
|
+
{
|
|
71
|
+
"event": "两线在第 20 章交汇",
|
|
72
|
+
"involved_storylines": ["main-arc", "faction-war"],
|
|
73
|
+
"target_chapter_range": [18, 22]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
关键字段:
|
|
80
|
+
|
|
81
|
+
- `secondary_min_appearance`:副线最小出场间隔(如 `every_8_chapters` = 每 8 章至少出现 1 次)
|
|
82
|
+
- `convergence_events`:交汇事件——多条线在指定章节范围内汇合
|
|
83
|
+
|
|
84
|
+
## 防串线机制
|
|
85
|
+
|
|
86
|
+
三层防护:
|
|
87
|
+
|
|
88
|
+
1. **结构化 Context**:ChapterWriter 每次只接收当前章相关的故事线状态,而非全部
|
|
89
|
+
2. **反串线指令**:prompt 中明确标注「本章属于 X 线,不得出现 Y 线的信息」
|
|
90
|
+
3. **QualityJudge 后验**:LS-005 规则检查跨线实体是否泄漏
|
|
91
|
+
|
|
92
|
+
每次续写都是独立的 LLM 调用,不依赖前一章的会话历史。
|
|
93
|
+
|
|
94
|
+
## 交汇事件
|
|
95
|
+
|
|
96
|
+
当多条故事线需要汇合时(如主角终于遇到暗线反派),在 `convergence_events` 中定义:
|
|
97
|
+
|
|
98
|
+
- 涉及哪些线
|
|
99
|
+
- 目标章节范围
|
|
100
|
+
- 交汇后的状态变化
|
|
101
|
+
|
|
102
|
+
卷末回顾时,系统会检查交汇事件是否在预定范围内达成。
|
|
103
|
+
|
|
104
|
+
## 故事线记忆
|
|
105
|
+
|
|
106
|
+
每条故事线有独立记忆文件 `storylines/{id}/memory.md`(≤500 字),由 Summarizer 每章更新。
|
|
107
|
+
|
|
108
|
+
记忆文件记录这条线的关键事实,供 ChapterWriter 写作时参考,避免遗忘已建立的设定。
|
|
109
|
+
|
|
110
|
+
## 桥梁关系
|
|
111
|
+
|
|
112
|
+
故事线之间可以定义桥梁(bridge),表示两条线通过共享伏笔或角色关联:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"relationships": [
|
|
117
|
+
{
|
|
118
|
+
"from": "main-arc",
|
|
119
|
+
"to": "conspiracy",
|
|
120
|
+
"type": "bridge:shared_foreshadowing",
|
|
121
|
+
"bridges": {
|
|
122
|
+
"shared_foreshadowing": ["foreshadow-id-1", "foreshadow-id-2"]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
卷末回顾时,系统检查桥梁是否断链(共享伏笔是否在全局索引中存在)。
|
|
130
|
+
|
|
131
|
+
## 日常操作
|
|
132
|
+
|
|
133
|
+
| 场景 | 操作 |
|
|
134
|
+
|------|------|
|
|
135
|
+
| 新增故事线 | 卷规划时由 PlotArchitect 建议,你确认 |
|
|
136
|
+
| 暂停故事线 | 将 status 改为 `dormant`(不计入活跃线) |
|
|
137
|
+
| 合并故事线 | 交汇事件达成后,将一条线标记为 `resolved` |
|
|
138
|
+
| 查看节奏 | `/novel:status` 展示各线出场频率和休眠提醒 |
|
|
139
|
+
|
|
140
|
+
## 注意事项
|
|
141
|
+
|
|
142
|
+
- 故事线 ID 用连字符(`main-arc`),类型用下划线 + `type:` 前缀(`type:main_arc`)
|
|
143
|
+
- 不要手动编辑 `storylines/storylines.json`,通过 `/novel:start` → 更新设定来操作
|
|
144
|
+
- 多线体系的完整能力在卷规划阶段才会展开,快速起步阶段保持简单
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "novel-writer-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Executor-agnostic novel orchestration CLI",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"novel": "dist/cli.js",
|
|
9
|
+
"novel-writer-cli": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"agents/",
|
|
14
|
+
"skills/",
|
|
15
|
+
"schemas/",
|
|
16
|
+
"scripts/",
|
|
17
|
+
"templates/",
|
|
18
|
+
"docs/user/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/DankerMu/novel-writer-cli.git"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/DankerMu/novel-writer-cli/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/DankerMu/novel-writer-cli#readme",
|
|
30
|
+
"scripts": {
|
|
31
|
+
"dev": "tsx src/cli.ts",
|
|
32
|
+
"build": "tsc -p tsconfig.json",
|
|
33
|
+
"start": "node dist/cli.js",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"test": "npm run build && node --test dist/__tests__/*.test.js"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"commander": "^14.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^24.0.0",
|
|
42
|
+
"tsx": "^4.20.0",
|
|
43
|
+
"typescript": "^5.9.0"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# JSON Schemas
|
|
2
|
+
|
|
3
|
+
This directory contains machine-readable JSON Schemas that act as **single sources of truth** (SSOT) for project-facing JSON/JSONL files.
|
|
4
|
+
|
|
5
|
+
## Integration plan
|
|
6
|
+
|
|
7
|
+
- Templates SHOULD be derived from these schemas (and may include a `$schema` pointer for editor tooling).
|
|
8
|
+
- Runtime validators SHOULD validate project files against these schemas (e.g., via Ajv or python-jsonschema) and fail fast on enum/range violations.
|
|
9
|
+
- Specs SHOULD reference the schema path instead of duplicating field definitions.
|
|
10
|
+
|
|
11
|
+
## Available schemas
|
|
12
|
+
|
|
13
|
+
- `schemas/platform-profile.schema.json` — `platform-profile.json` (M6 baseline + M7 optional extensions)
|
|
14
|
+
- `schemas/hook-ledger.schema.json` — `hook-ledger.json` (M7 retention hook ledger)
|
|
15
|
+
- `schemas/promise-ledger.schema.json` — `promise-ledger.json` (M7 long-horizon narrative promise ledger)
|
|
16
|
+
- `schemas/engagement-metrics.schema.json` — `engagement-metrics.jsonl` record (M7 engagement density stream)
|
|
17
|
+
- `schemas/character-voice-profiles.schema.json` — `character-voice-profiles.json` (M7 per-character voice profiles)
|
|
18
|
+
- `schemas/character-voice-drift.schema.json` — `character-voice-drift.json` (M7 voice drift directives)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"schema_version": 1,
|
|
4
|
+
"title": "character-voice-drift.json",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "generated_at", "as_of", "window", "profiles_path", "characters"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Optional schema pointer for editor tooling. Example: schemas/character-voice-drift.schema.json"
|
|
12
|
+
},
|
|
13
|
+
"schema_version": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"enum": [1],
|
|
16
|
+
"description": "Schema version of character-voice-drift.json (SSOT in schemas/character-voice-drift.schema.json)."
|
|
17
|
+
},
|
|
18
|
+
"generated_at": { "type": "string", "format": "date-time" },
|
|
19
|
+
"as_of": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"required": ["chapter", "volume"],
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"properties": {
|
|
24
|
+
"chapter": { "type": "integer", "minimum": 1 },
|
|
25
|
+
"volume": { "type": "integer", "minimum": 0 }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"window": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"required": ["chapter_start", "chapter_end", "window_chapters"],
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"properties": {
|
|
33
|
+
"chapter_start": { "type": "integer", "minimum": 1 },
|
|
34
|
+
"chapter_end": { "type": "integer", "minimum": 1 },
|
|
35
|
+
"window_chapters": { "type": "integer", "minimum": 1 }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"profiles_path": { "type": "string", "minLength": 1 },
|
|
39
|
+
"characters": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"items": { "$ref": "#/$defs/character" }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"$defs": {
|
|
45
|
+
"drifted_metric": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"required": ["id", "baseline", "current", "detail"],
|
|
48
|
+
"additionalProperties": false,
|
|
49
|
+
"properties": {
|
|
50
|
+
"id": { "type": "string", "minLength": 1 },
|
|
51
|
+
"baseline": { "type": "number" },
|
|
52
|
+
"current": { "type": "number" },
|
|
53
|
+
"detail": { "type": "string", "minLength": 1 }
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"signature_phrases": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"required": ["baseline", "current", "overlap"],
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"properties": {
|
|
61
|
+
"baseline": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
62
|
+
"current": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
63
|
+
"overlap": { "type": ["number", "null"], "minimum": 0, "maximum": 1 }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"metrics": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"required": [
|
|
69
|
+
"dialogue_samples",
|
|
70
|
+
"dialogue_chars",
|
|
71
|
+
"dialogue_len_avg",
|
|
72
|
+
"dialogue_len_p25",
|
|
73
|
+
"dialogue_len_p50",
|
|
74
|
+
"dialogue_len_p75",
|
|
75
|
+
"sentence_len_avg",
|
|
76
|
+
"sentence_len_p25",
|
|
77
|
+
"sentence_len_p50",
|
|
78
|
+
"sentence_len_p75",
|
|
79
|
+
"exclamation_per_100_chars",
|
|
80
|
+
"question_per_100_chars",
|
|
81
|
+
"ellipsis_per_100_chars"
|
|
82
|
+
],
|
|
83
|
+
"additionalProperties": false,
|
|
84
|
+
"properties": {
|
|
85
|
+
"dialogue_samples": { "type": "integer", "minimum": 0 },
|
|
86
|
+
"dialogue_chars": { "type": "integer", "minimum": 0 },
|
|
87
|
+
"dialogue_len_avg": { "type": "number", "minimum": 0 },
|
|
88
|
+
"dialogue_len_p25": { "type": "integer", "minimum": 0 },
|
|
89
|
+
"dialogue_len_p50": { "type": "integer", "minimum": 0 },
|
|
90
|
+
"dialogue_len_p75": { "type": "integer", "minimum": 0 },
|
|
91
|
+
"sentence_len_avg": { "type": "number", "minimum": 0 },
|
|
92
|
+
"sentence_len_p25": { "type": "integer", "minimum": 0 },
|
|
93
|
+
"sentence_len_p50": { "type": "integer", "minimum": 0 },
|
|
94
|
+
"sentence_len_p75": { "type": "integer", "minimum": 0 },
|
|
95
|
+
"exclamation_per_100_chars": { "type": "number", "minimum": 0 },
|
|
96
|
+
"question_per_100_chars": { "type": "number", "minimum": 0 },
|
|
97
|
+
"ellipsis_per_100_chars": { "type": "number", "minimum": 0 }
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"evidence": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"required": ["chapter", "excerpt"],
|
|
103
|
+
"additionalProperties": false,
|
|
104
|
+
"properties": {
|
|
105
|
+
"chapter": { "type": "integer", "minimum": 1 },
|
|
106
|
+
"excerpt": { "type": "string", "minLength": 1 }
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"character": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"required": [
|
|
112
|
+
"character_id",
|
|
113
|
+
"display_name",
|
|
114
|
+
"drifted_metrics",
|
|
115
|
+
"signature_phrases",
|
|
116
|
+
"baseline_metrics",
|
|
117
|
+
"current_metrics",
|
|
118
|
+
"evidence",
|
|
119
|
+
"directives"
|
|
120
|
+
],
|
|
121
|
+
"additionalProperties": false,
|
|
122
|
+
"properties": {
|
|
123
|
+
"character_id": { "type": "string", "minLength": 1 },
|
|
124
|
+
"display_name": { "type": "string", "minLength": 1 },
|
|
125
|
+
"drifted_metrics": { "type": "array", "items": { "$ref": "#/$defs/drifted_metric" } },
|
|
126
|
+
"signature_phrases": { "$ref": "#/$defs/signature_phrases" },
|
|
127
|
+
"baseline_metrics": { "$ref": "#/$defs/metrics" },
|
|
128
|
+
"current_metrics": { "$ref": "#/$defs/metrics" },
|
|
129
|
+
"evidence": { "type": "array", "items": { "$ref": "#/$defs/evidence" } },
|
|
130
|
+
"directives": { "type": "array", "items": { "type": "string", "minLength": 1 } }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"schema_version": 1,
|
|
4
|
+
"title": "character-voice-profiles.json",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "created_at", "selection", "policy", "profiles"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"patternProperties": {
|
|
9
|
+
"^_.*$": { "$ref": "#/$defs/comment_value" }
|
|
10
|
+
},
|
|
11
|
+
"propertyNames": {
|
|
12
|
+
"not": { "enum": ["__proto__", "constructor", "prototype"] }
|
|
13
|
+
},
|
|
14
|
+
"properties": {
|
|
15
|
+
"$schema": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Optional schema pointer for editor tooling. Example: schemas/character-voice-profiles.schema.json"
|
|
18
|
+
},
|
|
19
|
+
"schema_version": {
|
|
20
|
+
"type": "integer",
|
|
21
|
+
"enum": [1],
|
|
22
|
+
"description": "Schema version of character-voice-profiles.json (SSOT in schemas/character-voice-profiles.schema.json)."
|
|
23
|
+
},
|
|
24
|
+
"created_at": { "type": "string", "format": "date-time" },
|
|
25
|
+
"selection": { "$ref": "#/$defs/selection" },
|
|
26
|
+
"policy": { "$ref": "#/$defs/policy" },
|
|
27
|
+
"profiles": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"items": { "$ref": "#/$defs/profile" }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"$defs": {
|
|
33
|
+
"comment_value": {
|
|
34
|
+
"description": "Free-form comment fields supported by templates/specs.",
|
|
35
|
+
"type": ["string", "number", "boolean", "null", "object", "array"]
|
|
36
|
+
},
|
|
37
|
+
"selection": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": ["protagonist_id"],
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"properties": {
|
|
42
|
+
"protagonist_id": { "type": "string", "minLength": 1 },
|
|
43
|
+
"core_cast_ids": { "type": "array", "items": { "type": "string", "minLength": 1 } }
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"thresholds": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"required": [
|
|
49
|
+
"avg_dialogue_chars_ratio_low",
|
|
50
|
+
"avg_dialogue_chars_ratio_high",
|
|
51
|
+
"exclamation_per_100_chars_delta",
|
|
52
|
+
"question_per_100_chars_delta",
|
|
53
|
+
"ellipsis_per_100_chars_delta",
|
|
54
|
+
"signature_overlap_min"
|
|
55
|
+
],
|
|
56
|
+
"additionalProperties": false,
|
|
57
|
+
"properties": {
|
|
58
|
+
"avg_dialogue_chars_ratio_low": { "type": "number", "exclusiveMinimum": 0 },
|
|
59
|
+
"avg_dialogue_chars_ratio_high": { "type": "number", "exclusiveMinimum": 0 },
|
|
60
|
+
"exclamation_per_100_chars_delta": { "type": "number", "minimum": 0 },
|
|
61
|
+
"question_per_100_chars_delta": { "type": "number", "minimum": 0 },
|
|
62
|
+
"ellipsis_per_100_chars_delta": { "type": "number", "minimum": 0 },
|
|
63
|
+
"signature_overlap_min": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"policy": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"required": ["window_chapters", "min_dialogue_samples", "drift_thresholds", "recovery_thresholds"],
|
|
69
|
+
"additionalProperties": false,
|
|
70
|
+
"properties": {
|
|
71
|
+
"window_chapters": { "type": "integer", "minimum": 1 },
|
|
72
|
+
"min_dialogue_samples": { "type": "integer", "minimum": 1 },
|
|
73
|
+
"drift_thresholds": { "$ref": "#/$defs/thresholds" },
|
|
74
|
+
"recovery_thresholds": { "$ref": "#/$defs/thresholds" }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"metrics": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": [
|
|
80
|
+
"dialogue_samples",
|
|
81
|
+
"dialogue_chars",
|
|
82
|
+
"dialogue_len_avg",
|
|
83
|
+
"dialogue_len_p25",
|
|
84
|
+
"dialogue_len_p50",
|
|
85
|
+
"dialogue_len_p75",
|
|
86
|
+
"sentence_len_avg",
|
|
87
|
+
"sentence_len_p25",
|
|
88
|
+
"sentence_len_p50",
|
|
89
|
+
"sentence_len_p75",
|
|
90
|
+
"exclamation_per_100_chars",
|
|
91
|
+
"question_per_100_chars",
|
|
92
|
+
"ellipsis_per_100_chars"
|
|
93
|
+
],
|
|
94
|
+
"additionalProperties": false,
|
|
95
|
+
"properties": {
|
|
96
|
+
"dialogue_samples": { "type": "integer", "minimum": 0 },
|
|
97
|
+
"dialogue_chars": { "type": "integer", "minimum": 0 },
|
|
98
|
+
"dialogue_len_avg": { "type": "number", "minimum": 0 },
|
|
99
|
+
"dialogue_len_p25": { "type": "integer", "minimum": 0 },
|
|
100
|
+
"dialogue_len_p50": { "type": "integer", "minimum": 0 },
|
|
101
|
+
"dialogue_len_p75": { "type": "integer", "minimum": 0 },
|
|
102
|
+
"sentence_len_avg": { "type": "number", "minimum": 0 },
|
|
103
|
+
"sentence_len_p25": { "type": "integer", "minimum": 0 },
|
|
104
|
+
"sentence_len_p50": { "type": "integer", "minimum": 0 },
|
|
105
|
+
"sentence_len_p75": { "type": "integer", "minimum": 0 },
|
|
106
|
+
"exclamation_per_100_chars": { "type": "number", "minimum": 0 },
|
|
107
|
+
"question_per_100_chars": { "type": "number", "minimum": 0 },
|
|
108
|
+
"ellipsis_per_100_chars": { "type": "number", "minimum": 0 }
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"profile": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"required": ["character_id", "display_name", "baseline_range", "baseline_metrics", "signature_phrases"],
|
|
114
|
+
"additionalProperties": false,
|
|
115
|
+
"patternProperties": {
|
|
116
|
+
"^_.*$": { "$ref": "#/$defs/comment_value" }
|
|
117
|
+
},
|
|
118
|
+
"propertyNames": {
|
|
119
|
+
"not": { "enum": ["__proto__", "constructor", "prototype"] }
|
|
120
|
+
},
|
|
121
|
+
"properties": {
|
|
122
|
+
"character_id": { "type": "string", "minLength": 1 },
|
|
123
|
+
"display_name": { "type": "string", "minLength": 1 },
|
|
124
|
+
"name_variants": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
125
|
+
"baseline_range": {
|
|
126
|
+
"type": "object",
|
|
127
|
+
"required": ["chapter_start", "chapter_end"],
|
|
128
|
+
"additionalProperties": false,
|
|
129
|
+
"properties": {
|
|
130
|
+
"chapter_start": { "type": "integer", "minimum": 1 },
|
|
131
|
+
"chapter_end": { "type": "integer", "minimum": 1 }
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"baseline_metrics": { "$ref": "#/$defs/metrics" },
|
|
135
|
+
"signature_phrases": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
136
|
+
"taboo_phrases": { "type": "array", "items": { "type": "string", "minLength": 1 } }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"schema_version": 1,
|
|
4
|
+
"title": "engagement-metrics.jsonl record",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schema_version",
|
|
8
|
+
"generated_at",
|
|
9
|
+
"chapter",
|
|
10
|
+
"volume",
|
|
11
|
+
"word_count",
|
|
12
|
+
"plot_progression_beats",
|
|
13
|
+
"conflict_intensity",
|
|
14
|
+
"payoff_score",
|
|
15
|
+
"new_info_load_score",
|
|
16
|
+
"notes"
|
|
17
|
+
],
|
|
18
|
+
"additionalProperties": false,
|
|
19
|
+
"propertyNames": {
|
|
20
|
+
"not": { "enum": ["__proto__", "constructor", "prototype"] }
|
|
21
|
+
},
|
|
22
|
+
"properties": {
|
|
23
|
+
"schema_version": {
|
|
24
|
+
"type": "integer",
|
|
25
|
+
"enum": [1],
|
|
26
|
+
"description": "Schema version of each engagement-metrics.jsonl record."
|
|
27
|
+
},
|
|
28
|
+
"generated_at": { "type": "string", "format": "date-time" },
|
|
29
|
+
"chapter": { "type": "integer", "minimum": 1 },
|
|
30
|
+
"volume": { "type": "integer", "minimum": 0 },
|
|
31
|
+
"word_count": { "type": "integer", "minimum": 0 },
|
|
32
|
+
"plot_progression_beats": { "type": "integer", "minimum": 0 },
|
|
33
|
+
"conflict_intensity": { "type": "integer", "minimum": 1, "maximum": 5 },
|
|
34
|
+
"payoff_score": { "type": "integer", "minimum": 1, "maximum": 5 },
|
|
35
|
+
"new_info_load_score": { "type": "integer", "minimum": 1, "maximum": 5 },
|
|
36
|
+
"notes": { "type": "string", "minLength": 1, "pattern": "\\S", "maxLength": 320 }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"schema_version": 1,
|
|
4
|
+
"title": "hook-ledger.json",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "entries"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"patternProperties": {
|
|
9
|
+
"^_.*$": { "$ref": "#/$defs/comment_value" }
|
|
10
|
+
},
|
|
11
|
+
"properties": {
|
|
12
|
+
"$schema": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Optional schema pointer for editor tooling. Example: schemas/hook-ledger.schema.json"
|
|
15
|
+
},
|
|
16
|
+
"schema_version": {
|
|
17
|
+
"type": "integer",
|
|
18
|
+
"enum": [1],
|
|
19
|
+
"description": "Schema version of hook-ledger.json (SSOT in schemas/hook-ledger.schema.json)."
|
|
20
|
+
},
|
|
21
|
+
"entries": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": { "$ref": "#/$defs/hook_ledger_entry" }
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"$defs": {
|
|
27
|
+
"comment_value": {
|
|
28
|
+
"description": "Free-form comment fields supported by templates/specs.",
|
|
29
|
+
"type": ["string", "number", "boolean", "null", "object", "array"]
|
|
30
|
+
},
|
|
31
|
+
"hook_ledger_entry": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": [
|
|
34
|
+
"id",
|
|
35
|
+
"chapter",
|
|
36
|
+
"hook_type",
|
|
37
|
+
"hook_strength",
|
|
38
|
+
"promise_text",
|
|
39
|
+
"status",
|
|
40
|
+
"fulfillment_window",
|
|
41
|
+
"fulfilled_chapter",
|
|
42
|
+
"created_at",
|
|
43
|
+
"updated_at"
|
|
44
|
+
],
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"patternProperties": {
|
|
47
|
+
"^_.*$": { "$ref": "#/$defs/comment_value" }
|
|
48
|
+
},
|
|
49
|
+
"properties": {
|
|
50
|
+
"id": { "type": "string", "minLength": 1 },
|
|
51
|
+
"chapter": { "type": "integer", "minimum": 1 },
|
|
52
|
+
"hook_type": { "type": "string", "minLength": 1 },
|
|
53
|
+
"hook_strength": { "type": "integer", "minimum": 1, "maximum": 5 },
|
|
54
|
+
"promise_text": { "type": "string", "minLength": 1 },
|
|
55
|
+
"status": { "type": "string", "enum": ["open", "fulfilled", "lapsed"] },
|
|
56
|
+
"fulfillment_window": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"minItems": 2,
|
|
59
|
+
"maxItems": 2,
|
|
60
|
+
"items": { "type": "integer", "minimum": 1 }
|
|
61
|
+
},
|
|
62
|
+
"fulfilled_chapter": {
|
|
63
|
+
"type": ["integer", "null"],
|
|
64
|
+
"minimum": 1
|
|
65
|
+
},
|
|
66
|
+
"created_at": { "type": "string", "format": "date-time" },
|
|
67
|
+
"updated_at": { "type": "string", "format": "date-time" },
|
|
68
|
+
"evidence_snippet": { "type": "string" },
|
|
69
|
+
"sources": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"properties": {
|
|
73
|
+
"eval_path": { "type": "string", "minLength": 1 }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"links": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"additionalProperties": false,
|
|
79
|
+
"properties": {
|
|
80
|
+
"promise_ids": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"items": { "type": "string", "minLength": 1 }
|
|
83
|
+
},
|
|
84
|
+
"foreshadowing_ids": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": { "type": "string", "minLength": 1 }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"history": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": {
|
|
93
|
+
"type": "object",
|
|
94
|
+
"required": ["at", "chapter", "action"],
|
|
95
|
+
"additionalProperties": false,
|
|
96
|
+
"properties": {
|
|
97
|
+
"at": { "type": "string", "format": "date-time" },
|
|
98
|
+
"chapter": { "type": "integer", "minimum": 1 },
|
|
99
|
+
"action": { "type": "string", "minLength": 1 },
|
|
100
|
+
"detail": { "type": "string" }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|