Procházet zdrojové kódy

Merge branch 'development' of github.com:visuddhinanda/mint into development

visuddhinanda před 1 týdnem
rodič
revize
4ca652ab33

+ 2 - 2
api-test/README.md

@@ -32,8 +32,8 @@ cd ../..
 
 ```bash
 cd api-test
-php run.php --username=test161 --password=12345            # 调 /v2/sign-in 换 token,跑全量
-php run.php --username=test161 --password=12345 --server=staging
+php run.php --username=<username> --password=<password>            # 调 /v2/sign-in 换 token,跑全量
+php run.php --username=<username> --password=<password>  --server=staging
 php run.php --token=<bearer>                                # 或直接给 token
 ```
 

+ 151 - 16
api-v13/documents/related-paragraphs-redesign.md

@@ -1,9 +1,13 @@
 # related_paragraphs 段落关联体系 修复设计文档
 
-> 状态:已评审;2026-03 对当前库(visuddhinanda_20260311)全量实测复核后修订,待实施
+> 状态:**第一批已实施**(2026-09-09,导出器 + 检测器落地于 `api-v13/scripts/related/`,
+> 第一版数据在影子表 `related_paragraphs_v1`,生产表未动);章回绕与 LLM 补齐两批待做。
 > 背景:2025-08 数据审计发现 related_paragraphs 存在多类系统性数据错误。
-> 原始生成链路(VRI html 锚点 → cs6_para.csv → Laravel 导入)中的 csv 文件已丢失,
-> 决定以 wbw_templates 为唯一数据源重新导出第一版数据,再用补丁文件修正历史问题。
+> 原始生成链路是 VRI html 锚点 → cs6_para.csv → Laravel 导入;决定以 wbw_templates
+> 为生成源重新导出第一版数据,再用补丁文件修正历史问题。
+>
+> **实施复核勘误见 §9**——其中 §6.1 关于 csv 已丢失的判断、§4.3 E8 的判据、
+> §6.2 关于义注 `{mula}_{cs}` 标记的语义三处与实测不符,正文已就地改正。
 
 ---
 
@@ -40,9 +44,11 @@ wbw_templates                (数据源头,逐词表)
   │                 按历史形态保留备注,导出器以实测词表为准)
   │   区间标记:      para151-152 / para151-152_sn4  (1 个 vri 段 ↔ 多个 cs,展开多行)
   │   缩写区间:      para292-3  = 292-293(M 补齐 N 的前缀)
-  │   义注文件:      dn1_0 / dn1_1({mula}_{cs},义注段挂 mūla 名下)
-  │   章节标记:      kn10_2 / an1_5(mūla 文件内的章界)
-  ▼  (旧链路经 cs6_para.csv ——已丢失,废弃)
+  │   章节标记:      dn1_0 / dn1_1 / kn10_2 / an5_1_1({book}_{章号},可多级)
+  │                 实测:mūla 与义注文件里形态相同,都是章界而非 cs 值;
+  │                 唯 _0 特殊,表示义注序言(→ {book}_A)。见 §9 勘误 3
+  │   书界标记:      dn1 / an3(纯书名,文件内的书切换点,93 行)
+  ▼  (旧链路经 cs6_para.csv ——仍存于 clove 仓库,含全部历史错误,只作基线不作源)
 related_paragraphs           (本表,631,838 行)
   book, para                 VRI 文件号 1-217 + 段落号
   book_id ──────────────────▶ book_titles.sn
@@ -85,7 +91,7 @@ pali_texts                   (全文)
 - 正常情况:一个 book_id 内只有一个 book_name 且 cs_para 单调递增(如 book=93)。
   现发现部分书不是:一个 book_id 内出现重复的 cs_para
 - related_paragraphs 数据当年从 wbw_templates(进而来自 VRI html 锚点)导入,
-  具体过程已不可考,cs6_para.csv 原始文件已丢失
+  具体过程已不可考,但 cs6_para.csv 本身仍在(见 §9),可用作逐段落比对基线
 
 ### 4.2 审计确认的正确性判据(修正后的业务模型)
 
@@ -108,8 +114,8 @@ pali_texts                   (全文)
 | E5 | book_id=0 未赋值 | 354 行(201 本各 1-3 行);book 189 审计时整本 1,572 行为 0,现已回填(1,570 行 book_id=230,仅书前页 2 行为 0) | 各文件 para 1-2 书前页(可接受)。sn=280/281 仍无 book_id 行:book 139 para≥925 整段归入 sn 157、book 214 para≥2162 整段归入 sn 276,随 book_id 层重跑修复。另 book_titles sn=230 title 误写 sādhuvilāsinī(与 sn=229 重名,实际应为 sīlakkhandhavaggaabhinavaṭīkā,已由 pali_texts level-1 标题证实) |
 | E6 | 覆盖缺口 | 3,466 段无行 | 主体为缩写区间丢失(见 E7),其余为 wbw_templates 整段缺失 |
 | E7 | **缩写区间丢失**(本次审计新发现) | 1,517 个标记段落 / 44 本:其中 1,292 段(85.2%)无 related 行,其余 225 段带行但 cs 全为乱码值(与 E1 同根) | VRI 缩写语法 `para292-3`(=292-293)旧生成器不识别:多数直接跳过,少数误解析为废值(如 `para32-3`→11,749、`para15-8`→44,058) |
-| E8 | **书边界污染平铺** | kaṅkhāvitaraṇī 义注 1,499 行 cs 恒 75、ṭīkā 669 行 cs 恒 0 等 | 换书(book_id 切换)后无标记,旧生成器无限沿用上一个 cs 值 |
-| E9 | 无标记书 | 16 本(book 8,15,16,25,37,39-42,44,45,47,48,56,61,129)related 有行但 wbw_templates 零标记 | VRI 源文件无锚点。其中 book 129(theragāthā-aṭṭhakathā 后半)等存在真实注释关系,需外部手段补齐 |
+| E8 | **书边界污染平铺** | 判据收窄后实测**仅 1 段**:book 207 / book_id 259 kaṅkhāvitaraṇī 义注 1,499 行 cs 恒 75(见 §9 勘误 2) | 换书(book_id 切换)后无标记,旧生成器无限沿用上一个 cs 值 |
+| E9 | 无标记书 | 16 本(book 8,15,16,25,37,39-42,44,45,47,48,56,61,129)related 有行但 wbw_templates 零标记 | VRI 源文件无锚点。其中 book 129(theragāthā-aṭṭhakathā 后半)存在真实注释关系——外部手段已找到:cs6_para.csv 里它有 6,580 非零行,直接回填即可,不需 LLM。其余 15 本 csv 里也是全零,源头就没有 |
 | E10 | 自造名体系 | NK(book 1,namakkāra 自注释对)、subo(book 10↔11)、dict(book 21↔9) | 非 SC 体系书对的自造 album 名,连接各自 mūla↔注释。架构正确(与 dn1/dn1_A 同构),保留不动;仅其中的乱码/缩写问题随全局规则修复 |
 
 ## 5. 全库书况初步分析表
@@ -122,7 +128,8 @@ pali_texts                   (全文)
 - **缩写丢失 n 处**:缩写区间标记段落无行 → 新导出器自动修复
 - **章回绕 n 次**:cs 重置计数 → 章后缀方案处理(注:含少量合法多轮注释结构
   如 NK 的 ṭīkā 两轮注释,处理时用标题层级甄别)
-- **无标记污染**:cs 值种类极少但行数巨大(书边界沿用平铺)→ 导出器留空 + LLM 补丁
+- **无标记污染**:整段无 cs 标记却被写进非零 cs(书边界沿用平铺)→ 导出器输出 cs=0 + LLM 补丁
+  (注:表内按旧判据「cs 值种类极少」标注的几本实为章回绕误判,见 §9 勘误 2)
 - **全书无标记**:wbw_templates 无任何 para 标记但 related 有行 → LLM 补丁或维持现状
 - **无 book_id 行**:sn 存在但无任何 book_id 归属行(行均被归入同文件前一册)
 
@@ -433,7 +440,11 @@ wbw_templates(唯一数据源,含全部 .ctl. 标记)
 ```
 
 关键决策记录:
-- **cs6_para.csv 废弃**,不再寻找;一切从 wbw_templates 重放
+- **cs6_para.csv 不作生成源**:它是现表的来源、含全部历史错误,一切从 wbw_templates
+  重放。但它并未丢失(`github.com/iapt-platform/clove/pali_title/cs6_para.csv`,523,283 行),
+  已归档为逐段落 diff 基线,并作为 book 129 的唯一回填源(见 §9)
+- **段落全集取 pali_texts 而非 wbw_templates**:pali_texts 523,284 段是严格超集,
+  wbw 少的 7,171 段散在 21 本里;wbw 只负责提供标记
 - **维持 VRI 编号方案**(章内局部编号),SC 数据不采用(SC 层级树与加后缀方案无本质
   区别,且 SC 为 Mahāsaṅgīti 独立校勘本,文本与 VRI 不对齐,无法直接落到 VRI 段落)
 - **回绕处理(分两类)**:
@@ -462,6 +473,7 @@ wbw_templates(唯一数据源,含全部 .ctl. 标记)
 | `paraN-M`(M 位数<N,补齐后>N) | 缩写区间,前缀补齐展开(para292-3→292,293) |
 | `paraN-M_book`(缩写+后缀组合,实测 989 行,如 `para1008-9_sn5`) | 先按缩写规则展开 N..M,再以后缀定 book_name |
 | `paraN-M-K...` | 链式首尾法展开 N..tail(para292-3-6→292..296);实测仅 4 行,旧数据已正确展开(book 189 para 827 → 292-296) |
+| `paraN-M`(M < N 且位数相同,全库 3 行) | 倒序区间=高位笔误,丢弃右端高位、只用低位重新前缀补齐(`para504-407`→504-507、`para706-608`→706-708),并记 issue 人工复核。见 §9 勘误 4 |
 | `paraN-`(M 空,全库仅 1 处:book 11 para 1577) | 留空 + issue(`truncated_marker`),人工定 |
 | 解析值超值域保护阈值 | 拒绝输出 + issue(`cs_out_of_range`),防乱码 |
 | 页码/卷标 `P/M/V/T/O` × 0-5(实测 26 家族 165,907 行) | 忽略,本轮不处理 |
@@ -472,7 +484,7 @@ wbw_templates(唯一数据源,含全部 .ctl. 标记)
 | 输入 | 处理 |
 |---|---|
 | 延续段(同书内有前一标记) | 沿用;区间沿用则整区间展开(含巨区间 844 行场景) |
-| 书边界(book_id 切换)后的无标记段 | **留空 + issue(`no_marker_after_book_switch`)** ⭐ 防污染核心规则 |
+| 书边界(book_id 切换)后的无标记段 | **输出 cs=0 + issue(`segment_without_markers`)** ⭐ 防污染核心规则。实测不能整段不输出:这些段落多是 cs=0 占位行(E4 的无注释体系书、义注序言、书前页),删掉会白丢 20,433 段覆盖,而 `index()` 取锚点要求 `cs_para > 0`,cs=0 行不产生任何配对 |
 | 文件开头段(para 1-2) | cs=0、book_id=0(维持现状语义) |
 | wbw_templates 整段无行 | 自然无输出 + issue(`missing_wbw`) |
 
@@ -482,9 +494,9 @@ wbw_templates(唯一数据源,含全部 .ctl. 标记)
 |---|---|
 | `paraN_book` 后缀 | book_name = 后缀 |
 | 无后缀标记 | 继承当前 book_name;文件开头继承不到 → 留空 + issue |
-| `{mula}_{0}`(义注文件) | 进入 `{mula}_A` 序言模式(重现 dn1_A 正确先例) |
-| `{mula}_{N>0}`(义注文件) | 退出序言模式,book_name=mūla 名 |
-| `{book}_{N}`(mūla 文件) | 章切换事件,触发章后缀上下文 |
+| `{book}_{0}` | 进入 `{book}_A` 序言模式(重现 dn1_A 正确先例) |
+| `{book}_{N>0}` | 退出序言模式;章切换事件,触发章后缀上下文。**不产生 cs 值**——mūla 与义注文件同形同义,见 §9 勘误 3 |
+| 序言段内出现 `paraN_{mula}` 后缀 | 只赋 cs、不夺名,book_name 保持 `{book}_A`。序言里带这种标记是正常体例(book 130 的 `mn1_0` 序言内就有 `para1_mn1`),序言只由 `{book}_{N>0}` 结束 |
 | NK/subo/dict 等自造名 | 由书级配置表提供(保兼容,不重新发明);books 107/143/144 的 kn10 家族导出名同样由书级配置表决定(补丁 old 值必须与之匹配,见 §6.5) |
 
 文件类型(义注 vs mūla)用 tag(aṭṭhakathā/ṭīkā vs mūla/pāḷi)消解
@@ -624,6 +636,129 @@ saṅghādisesa 从 1 重计),修复时按组加后缀(vin6_pr1 型),
 - 标记词表:缩写+后缀组合 `para1008-9_sn5` 型 989 行;链式标记 4 行(旧数据已正确
   展开);截断 `para179-` 仅 book 11 para 1577 一处;页码标记 26 家族 165,907 行
   (本轮忽略);纯书名标记 93 行(书上下文事件);巨区间 para308-1151 现为 844 行。
-- 基础环境:cs6_para.csv 确认已不存在(storage/resources/pali_title 目录缺失);
+- 基础环境:本地 storage/resources/pali_title 目录缺失,但 csv 在 clove 仓库里(见 §9);
   281 个 sn 与 book_titles 一致;tags 的 8 个类型名齐备,文件类型消歧可用;
   新导出器 command 尚未实现,本文档仍处于待实施状态。
+
+---
+
+## 9. 实施复核勘误与新发现(2026-09-09,第一批实施)
+
+工具链落地于 `api-v13/scripts/related/`,第一版数据在影子表 `related_paragraphs_v1`
+(638,076 行),生产表已备份为 `related_paragraphs_bak_20260909` 且未改动。
+以下是实施中与本文档原判断不符、或本文档未记录的事实,正文相应处已就地改正。
+
+### 勘误 1:cs6_para.csv 并未丢失
+
+在 `github.com/iapt-platform/clove/pali_title/cs6_para.csv`,523,283 行,可直接取得。
+本地 `storage/resources/pali_title` 目录确实缺失,§8 据此推断"文件已不存在"是过头了。
+
+它仍不能当生成源——它是现表的来源,含全部历史错误(`462580` 废值、`kn10_A`/`kn10_B`
+错名一个不少)。但两个用途不可替代:
+
+- **逐段落 diff 基线**:它每行一个段落带 `begin,end`,正是重放结果的天然对照
+- **book 129 的唯一回填源**:逐本比对「csv 非零行 vs wbw 标记数」,全库只有 book 129
+  是"csv 有 6,580 非零行、wbw 零标记"。E9 其余 15 本 csv 里也是全零,源头就没有。
+  也就是说这本不需要 LLM,直接回填即可
+
+另:`para504-407` 丢段的完整链路查清了——csv 里原样写着 `begin=504,end=407`,
+旧 Laravel 命令的 `for ($i = $begin; $i <= $end; $i++)` 一圈没进。**丢段发生在导入
+环节的静默空转,不在生成环节**。
+
+### 勘误 2:E8 判据过宽,真污染只有 1 段
+
+按"cs 值种类极少但行数巨大"判会把**章回绕误报成污染**:book 152 有 516 个 cs 标记却
+只有 24 个不同 cs 值,那是 22 次回绕造成的,不是平铺。
+
+污染的准确签名是「整段一个 cs 标记都没有,却被写进了非零 cs」——那个值只能是从上一本
+沿用下来的。按此判,全库只有 **book 207 / book_id 259 kaṅkhāvitaraṇī 一段,1,499 行
+恒 cs=75**。原列的其余几组:
+
+- book 212/273(669 行)、book 180/213(1,219 行)、book 209/261(163 行)cs 恒为 **0**
+  ——0 是"未赋值"不是编造值,不算污染
+- book 152/46/116/154/204 是章回绕(E2),归 E2 处理
+
+### 勘误 3:`{name}_{N}` 是章标记,mūla 与义注文件同形同义
+
+§2 原写"义注文件 `dn1_0 / dn1_1` 是 `{mula}_{cs}`,义注段挂 mūla 名下"。实测不是:
+
+- book 93(mūla)有 `dn1_1..dn1_13`,book 103(义注)有 `dn1_0..dn1_13`,**形态与语义都相同**,
+  都是章界,都不产生 cs 值
+- book 103 para 1460 的 `dn1_12` 并没有让该段 cs=12——该段 cs=499,来自 para 标记
+
+义注段挂 mūla 名下靠的是 **`paraN_{mula}` 后缀**(如 `para4_dn1`),不是章标记。
+唯一特殊的是 `_0`:它表示义注序言(Ganthārambhakathā),进入 `{book}_A` 模式。
+
+配套的两条实测语义:
+
+- **序言由 `{book}_{N>0}` 结束,不由 cs 标记结束**。book 103 的 `dn1_A` 止于 `dn1_1`@199,
+  与旧表的 198/199 分界严丝合缝
+- **序言段内出现 `paraN_{mula}` 是正常体例**。book 130 的 `mn1_0` 序言(paras 5-46)里就有
+  `para1_mn1`@40,book 192 更有一长串。这些后缀只赋 cs、不夺名,段落仍归 `{book}_A`
+
+### 勘误 4:两类本文档未记录的标记形态
+
+全库 330,267 个锚点(`type='.ctl.' and style='#a#'`)经解析器 100% 归类、零 unknown:
+page 167,647 / single 156,919 / interval 4,604 / chapter 1,003 / book_tag 93 / truncated 1。
+其中两类原文档没有:
+
+- **倒序区间 3 行**:`para504-407`(book 103 para 1464)、`para706-608`(book 176 para 753)。
+  是高位笔误,低位正确:前者前邻 502-503、后邻 508,真值 504–507;后者前邻 703-705、
+  后邻 709,真值 706–708。规则是丢弃右端高位、只用低位重新前缀补齐
+- **多级章标记 247 行 / 13 本**:`an5_1_1` 型。义注书 100-102 与 mūla 书 82-92 **共用同一套
+  编号**,这是 §6.1 跨侧章界对齐现成的抓手,做章后缀时应优先用它而非推标题
+
+### 新发现 5:段落全集是 pali_texts 不是 wbw_templates
+
+pali_texts 523,284 段是严格超集(正是 csv 的行数),wbw_templates 只有 516,113 段,
+少的 7,171 段散在 21 本里。按 wbw 取段落全集会白丢这些段落的行。wbw 只负责提供标记。
+
+### 新发现 6:两处书名归属错误
+
+- **book 107(apadāna-aṭṭhakathā)整本属 kn10**。旧表切成 `kn10_A`(para 3-2141) +
+  `kn10_B`(2142-3875) 并称后者对应 therī——标题证伪:para 2146 的标题是
+  `(Dutiyo bhāgo) Therāpadānaṃ`,那是 therāpadāna 的**第二卷**;全书只有一个 level-1
+  标题「Apadāna-aṭṭhakathā」,vagga 编到 56(Yasavaggo)也正是 therāpadāna 的范围,
+  书内无任何 therī 标题。therīapadāna 另在 book 144 para 6534 起。已记入
+  `book_config.json` 的 `overrides`
+- **book 177 内含四部书**:abhidhammāvatāro(sn 205)、nāmarūpaparicchedo(206)、
+  paramatthavinicchayo(207)、saccasaṅkhepo(208)。只有第一部是 `abhi8`,
+  后三部本就没有 SC 书名。生成书级配置表时若过滤掉空书名,`abhi8` 会越过书界铺满
+  整个文件,把 10,695 行错配进 abhi8 的注释链——空书名必须同样成段
+
+### 新发现 7:book 143/144 的 kn10 错名靠 wbw 自动修复
+
+E3 原以为需要人工改名。实测 wbw 里 book 143 有 `kn10@3`、book 144 有 `kn10@3` 与
+`kn11@6532`,书界写得清清楚楚,按 wbw 重放即自动归位。需人工的只有没有 book_tag 的
+book 107(见新发现 6)。
+
+### 第一批成绩
+
+| 探测器 | 旧表 | v1 |
+|---|---|---|
+| E1 cs 乱码 | 1,242 行 | **0** |
+| E3 kn10 | 0 行 | **25,506 行**(kn10_A/B 清零) |
+| E6 覆盖缺口 | 3,464 段 | **1 段**(仅 book 11 那个截断标记) |
+| E7 缩写区间丢失 | 1,292 段无行 + 225 段废值 | **0 + 0** |
+| E8 污染平铺 | 1,499 行 | **0** |
+| 区间展开不符 | 1,611 | **0** |
+| 镜像判据 | 559/1289/524/918 | **保持** |
+| 零错误信号的书 | 128 本 | **148 本** |
+
+与旧表逐段落 91.8% 相同(480,290 / 523,284 段)。差异全部归因:
+`only_in_old` 1 段(截断标记)、`only_in_new` 3,466 段(区间展开补回,与旧表覆盖缺口
+数吻合)、`cs_changed` 10,371 段(8,600 归零防污染 + 528 新赋值 + **1,290 两侧都非零而
+边界不同**)、`name_changed` 29,156 段(29,146 是 kn10 家族修复,余 10 段是各文件
+book_tag 所在段本身)。
+
+那 1,290 段是唯一需要人工判断的部分(占全库 0.25%)。已抽查 book 110 para 993-999:
+旧表把 cs=5 的边界提前了 7 段,而该区间内除页码外无任何标记,`para5` 标记在 para 1000,
+新值(延续 cs=4 至 999)有据、旧值无据。
+
+### 遗留
+
+1. E2 章回绕 677 处未处理(本批不做,先让确定性规则跑干净)
+2. book 129 的 6,605 段现为 cs=0 占位,待用 csv 回填
+3. 20 段 `segment_without_markers` 已输出 cs=0 占位,待 LLM 归属
+4. book 11 para 1577 的 `para179-` 截断标记待人工定
+5. 上述 1,290 段边界差异待抽样复核

+ 3 - 0
api-v13/scripts/related/.gitignore

@@ -0,0 +1,3 @@
+report/
+data/cs6_para.csv
+data/backup/

+ 300 - 0
api-v13/scripts/related/align_chapters.php

@@ -0,0 +1,300 @@
+<?php
+
+/**
+ * 章回绕的跨侧对齐:给每个 book_name 的每个「cs 重置段」定一个章号,两侧用同一套章号。
+ *
+ * 为什么不能各干各的:book 143(mūla kn10)有 42 个章标记,book 107(义注 kn10)一个
+ * 都没有。单方面按标记加后缀,会让 kn10_1 只出现在 mūla 侧、义注侧还叫 kn10,
+ * 两侧的配对全部打断——比不加后缀更糟。所以必须先对齐,再一起加。
+ *
+ * 对齐靠什么:注释侧的 cs 值就是被注书的段落号,所以两侧每一章的 max(cs) 应当接近
+ * (实测 kn10 前 11 章:663/657、140/134、188/184、113/108…,注释侧略低,因为它不注
+ * 每章最后几段)。但段数常对不上(kn10 mūla 42 段 vs 义注 34 段,中间还夹着 max=2 的
+ * 碎段),所以按序号硬配会漂,得做带空位的序列比对。
+ *
+ * 用法:
+ *   php scripts/related/align_chapters.php --table=related_paragraphs_v1
+ *   php scripts/related/align_chapters.php --table=related_paragraphs_v1 --name=kn10 --verbose
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$table = rp_assert_table($options['table'] ?? 'related_paragraphs_v1');
+$onlyName = $options['name'] ?? null;
+$verbose = isset($options['verbose']);
+/** 对齐得分低于此值的段判为不可信,不加后缀,转人工/LLM。 */
+$minConfidence = (float) ($options['min-confidence'] ?? 0.6);
+
+$log = new RpLogger('align_chapters', rp_report_dir());
+$log->info("被对齐表:{$table}");
+$log->info("置信度阈值:{$minConfidence}");
+
+$config = rp_json_read(__DIR__.'/book_config.json');
+
+/** 某 VRI 文件在注释链条中的位置。同一文件可能多种,取首个 level-1 的判定。 */
+$sideOf = function (int $book) use ($config): string {
+    $types = $config['books'][(string) $book]['file_types'] ?? [];
+
+    return $types[0]['type'] ?? 'unknown';
+};
+
+// ── 找出所有有回绕的 book_name ────────────────────────────────────────────
+$names = DB::select("
+    with s as (
+        select book_name, book, para, cs_para,
+               lag(cs_para) over (partition by book, book_name order by para, cs_para) as prev
+        from {$table} where cs_para > 0 and book_name <> ''
+    )
+    select book_name, count(*) as wraps
+    from s where cs_para = 1 and prev > 1
+    group by book_name order by count(*) desc
+");
+if ($onlyName) {
+    $names = array_values(array_filter($names, fn ($n) => $n->book_name === $onlyName));
+}
+$log->info('有回绕的 book_name:'.count($names).' 个');
+
+/**
+ * 把一个 (book_name, book) 的行切成「cs 重置段」。
+ *
+ * @return list<array{seg:int, book:int, para_from:int, para_to:int, cs_min:int, cs_max:int, rows:int}>
+ */
+$segmentsOf = function (string $name, int $book) use ($table): array {
+    $rows = DB::select("
+        select para, min(cs_para) as cs_min, max(cs_para) as cs_max
+        from {$table} where book_name = ? and book = ? and cs_para > 0
+        group by para order by para
+    ", [$name, $book]);
+
+    $segments = [];
+    $current = null;
+    $prevMin = null;
+    foreach ($rows as $r) {
+        // 按段落的 cs_min 判重置。用 cs_max 会被区间展开骗到:连续的 para1-2 段落
+        // 每段 cs 都是 {1,2},看 max 就成了 …2→1 的连环「重置」。
+        $isReset = $prevMin !== null && (int) $r->cs_min === 1 && $prevMin > 1;
+        if ($current === null || $isReset) {
+            if ($current !== null) {
+                $segments[] = $current;
+            }
+            $current = [
+                'seg' => count($segments), 'book' => $book,
+                'para_from' => (int) $r->para, 'para_to' => (int) $r->para,
+                'cs_min' => (int) $r->cs_min, 'cs_max' => (int) $r->cs_max, 'rows' => 0,
+            ];
+        }
+        $current['para_to'] = (int) $r->para;
+        $current['cs_max'] = max($current['cs_max'], (int) $r->cs_max);
+        $current['cs_min'] = min($current['cs_min'], (int) $r->cs_min);
+        $current['rows']++;
+        $prevMin = (int) $r->cs_min;
+    }
+    if ($current !== null) {
+        $segments[] = $current;
+    }
+
+    return $segments;
+};
+
+/** 两段 max(cs) 的接近程度,值域约 [-2, 2]。注释侧本就略低于 mūla,故不对称惩罚。 */
+$score = function (int $refMax, int $queryMax): float {
+    $scale = max($refMax, $queryMax, 1);
+    $diff = abs($refMax - $queryMax) / $scale;
+    $s = 2.0 - 4.0 * $diff;
+    if ($queryMax > $refMax) {
+        $s -= 0.5;   // 注释侧超过被注书的章长,不合体例,压一压
+    }
+
+    return $s;
+};
+
+/**
+ * 带空位的序列比对(Needleman–Wunsch)。
+ * 返回 query 段下标 → ref 段下标;对不上的段返回 null,由调用方并入前一章。
+ *
+ * @return array<int, ?int>
+ */
+$align = function (array $refMax, array $queryMax) use ($score): array {
+    $m = count($refMax);
+    $n = count($queryMax);
+    $gapRef = -0.6;      // 跳过一章参考段:该章没有注释,常见
+    $gapQuery = -1.2;    // 跳过一个查询段:多半是碎段,代价高些
+
+    $dp = array_fill(0, $m + 1, array_fill(0, $n + 1, 0.0));
+    $from = array_fill(0, $m + 1, array_fill(0, $n + 1, ''));
+    for ($i = 1; $i <= $m; $i++) {
+        $dp[$i][0] = $dp[$i - 1][0] + $gapRef;
+        $from[$i][0] = 'up';
+    }
+    for ($j = 1; $j <= $n; $j++) {
+        $dp[0][$j] = $dp[0][$j - 1] + $gapQuery;
+        $from[0][$j] = 'left';
+    }
+    for ($i = 1; $i <= $m; $i++) {
+        for ($j = 1; $j <= $n; $j++) {
+            $diag = $dp[$i - 1][$j - 1] + $score($refMax[$i - 1], $queryMax[$j - 1]);
+            $up = $dp[$i - 1][$j] + $gapRef;
+            $left = $dp[$i][$j - 1] + $gapQuery;
+            $best = max($diag, $up, $left);
+            $dp[$i][$j] = $best;
+            $from[$i][$j] = $best === $diag ? 'diag' : ($best === $up ? 'up' : 'left');
+        }
+    }
+
+    $map = [];
+    $i = $m;
+    $j = $n;
+    while ($i > 0 || $j > 0) {
+        $dir = $from[$i][$j];
+        if ($dir === 'diag') {
+            $map[$j - 1] = $i - 1;
+            $i--;
+            $j--;
+        } elseif ($dir === 'up') {
+            $i--;
+        } else {
+            $map[$j - 1] = null;
+            $j--;
+        }
+    }
+    ksort($map);
+
+    return $map;
+};
+
+$result = [];
+foreach ($names as $nameRow) {
+    $name = $nameRow->book_name;
+    $books = array_map(
+        fn ($r) => (int) $r->book,
+        DB::select("select distinct book from {$table} where book_name = ? order by book", [$name])
+    );
+
+    // 按侧分组,mūla 侧作参考;没有 mūla 侧就用行数最多的那一侧
+    $bySide = [];
+    foreach ($books as $book) {
+        $bySide[$sideOf($book)][] = $book;
+    }
+    $refSide = isset($bySide['mula']) ? 'mula' : array_key_first($bySide);
+    if ($refSide === null) {
+        $log->unresolved('chapter_align_no_side', ['book_name' => $name]);
+
+        continue;
+    }
+
+    // 参考侧的段序列(跨文件按 book 顺序拼接)即章号定义
+    $refSegments = [];
+    foreach ($bySide[$refSide] as $book) {
+        foreach ($segmentsOf($name, $book) as $s) {
+            $refSegments[] = $s;
+        }
+    }
+    if ($refSegments === []) {
+        continue;
+    }
+    $refMax = array_column($refSegments, 'cs_max');
+
+    $entry = [
+        'book_name' => $name,
+        'wraps' => (int) $nameRow->wraps,
+        'ref_side' => $refSide,
+        'ref_books' => $bySide[$refSide],
+        'chapters' => count($refSegments),
+        'assignments' => [],
+        'unaligned' => 0,
+        'confidence' => 1.0,
+    ];
+
+    $alignedTotal = 0;
+    $segTotal = 0;
+
+    foreach ($bySide as $side => $sideBooks) {
+        foreach ($sideBooks as $book) {
+            $segments = $segmentsOf($name, $book);
+            if ($segments === []) {
+                continue;
+            }
+
+            if ($side === $refSide) {
+                // 参考侧:段号即章号,但要按跨文件拼接后的全局下标
+                $offset = 0;
+                foreach ($bySide[$refSide] as $b) {
+                    if ($b === $book) {
+                        break;
+                    }
+                    $offset += count($segmentsOf($name, $b));
+                }
+                $map = [];
+                foreach (array_keys($segments) as $k) {
+                    $map[$k] = $offset + $k;
+                }
+            } else {
+                $map = $align($refMax, array_column($segments, 'cs_max'));
+            }
+
+            $lastChapter = null;
+            foreach ($segments as $k => $seg) {
+                $chapter = $map[$k] ?? null;
+                $segTotal++;
+                if ($chapter === null) {
+                    // 对不上的碎段并入前一章:它多半是注释侧的一次多余重置
+                    $chapter = $lastChapter;
+                    $entry['unaligned']++;
+                    $log->count('segment_merged_into_previous');
+                } else {
+                    $alignedTotal++;
+                    $lastChapter = $chapter;
+                }
+                if ($chapter === null) {
+                    $log->unresolved('chapter_align_orphan_segment', [
+                        'book_name' => $name, 'book' => $book,
+                        'para_from' => $seg['para_from'], 'para_to' => $seg['para_to'],
+                        'cs_max' => $seg['cs_max'],
+                    ]);
+
+                    continue;
+                }
+                $entry['assignments'][] = [
+                    'book' => $book, 'side' => $side,
+                    'para_from' => $seg['para_from'], 'para_to' => $seg['para_to'],
+                    'cs_max' => $seg['cs_max'],
+                    'chapter' => $chapter + 1,
+                    'ref_cs_max' => $refSegments[$chapter]['cs_max'],
+                ];
+            }
+        }
+    }
+
+    $entry['confidence'] = $segTotal > 0 ? round($alignedTotal / $segTotal, 3) : 0.0;
+    $entry['applicable'] = $entry['confidence'] >= $minConfidence && $entry['chapters'] > 1;
+    $result[$name] = $entry;
+
+    $log->info(sprintf('%-8s 章数 %-3d 段数 %-4d 对上 %-4d 置信 %.3f %s',
+        $name, $entry['chapters'], $segTotal, $alignedTotal, $entry['confidence'],
+        $entry['applicable'] ? '' : '← 置信不足,不加后缀'));
+
+    if ($verbose) {
+        foreach ($entry['assignments'] as $a) {
+            $log->info(sprintf('    book %-3d %-10s para %-6d-%-6d cs_max %-5d → 章 %-3d (参考 %d)',
+                $a['book'], $a['side'], $a['para_from'], $a['para_to'], $a['cs_max'],
+                $a['chapter'], $a['ref_cs_max']));
+        }
+    }
+}
+
+$applicable = array_filter($result, fn ($e) => $e['applicable']);
+$log->info(sprintf('可加后缀的 book_name:%d / %d', count($applicable), count($result)));
+
+$path = rp_report_dir().'/chapter_alignment.json';
+rp_json_write($path, [
+    'generated_at' => date('c'),
+    'table' => $table,
+    'min_confidence' => $minConfidence,
+    'names' => $result,
+]);
+$log->info("对齐表:{$path}");
+
+$log->finish();

+ 151 - 0
api-v13/scripts/related/apply_chapters.php

@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * 按 align_chapters.php 的对齐结果给 book_name 加章后缀,产出下一版表。
+ *
+ * 加后缀是为了让 (book_name, cs_para) 这个配对键重新变得唯一:回绕使同一个 key 在
+ * 几十个章里重复,index() 一次查询就把几十章的段落全捞回来。后缀必须两侧同时加、
+ * 用同一套章号,只给一侧加会把配对整个打断——所以只处理 align 判定为可信的 book_name,
+ * 其余原样留给补丁/LLM。
+ *
+ * 光靠 align 的置信度不够。实测 vin8 的 books 200/201 都覆盖 cs 1..3183(是并列的两侧,
+ * 不是上下册),却被当成顺序拼接标成了「第 1 章 / 第 2 章」,该名的跨文件配对 100% 报废;
+ * dict 的 books 9↔21 同理。侧别判定要做到永不出错是不现实的,所以每个 book_name 改名
+ * 前后都实测一次跨文件配对段数,掉了就整名回滚——指标说了算,不是规则说了算。
+ *
+ * 用法:
+ *   php scripts/related/apply_chapters.php --from=related_paragraphs_v1 --to=related_paragraphs_v2
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$from = rp_assert_table($options['from'] ?? 'related_paragraphs_v1');
+$to = rp_assert_table($options['to'] ?? 'related_paragraphs_v2');
+
+$log = new RpLogger('apply_chapters', rp_report_dir());
+$log->info("源表:{$from}");
+$log->info("目标表:{$to}");
+
+$alignment = rp_json_read(rp_report_dir().'/chapter_alignment.json');
+if ($alignment['table'] !== $from) {
+    $log->error("对齐表是针对 {$alignment['table']} 算的,与源表 {$from} 不符,先重跑 align_chapters.php");
+    $log->finish();
+    exit(1);
+}
+
+$log->info('复制源表…');
+DB::statement("drop table if exists {$to}");
+DB::statement("create table {$to} as select * from {$from}");
+DB::statement("create index on {$to} (book, para)");
+$log->info('行数:'.DB::table($to)->count());
+
+$applied = 0;
+$rowsChanged = 0;
+$reverted = 0;
+
+/**
+ * 某个 book_name(含其所有章后缀变体)下,有多少 (book, para) 通过**可信的**配对键
+ * 跨文件命中。可信 = 该键在任何单本书里命中的段落数不超过 $maxParas。
+ *
+ * 为什么要排除膨胀键:回绕让 kn10:1 这样的键在 56 个章里重复,一次查询捞回上千段,
+ * 那不是配对是噪声。直接数「配对段数」会把这些噪声算成资产——实测 kn10 加后缀后该数
+ * 从 23757 掉到 6279,看着像灾难,其实掉的几乎全是 book 144 章 43-56 的虚假配对
+ * (那几章本来就没有义注,是靠撞在一起的 kn10:1 假装配上的)。只数非膨胀键,
+ * 加对了后缀这个数会涨(膨胀键裂成一批干净键),加错了才会掉。
+ */
+$pairedParagraphs = function (string $table, string $baseName, int $maxParas = 10): int {
+    $pattern = str_replace(['_', '%'], ['\\_', '\\%'], $baseName);
+
+    return (int) DB::selectOne("
+        with mine as (
+            select book, para, book_name, cs_para
+            from {$table}
+            where cs_para > 0 and (book_name = ? or book_name like ?)
+        ),
+        per_book as (
+            select book_name, cs_para, book, count(distinct para) as paras
+            from mine group by book_name, cs_para, book
+        ),
+        k as (
+            select book_name, cs_para from per_book
+            group by book_name, cs_para
+            having count(*) >= 2 and max(paras) <= ?
+        )
+        select count(distinct (m.book, m.para))::int as n
+        from mine m join k on k.book_name = m.book_name and k.cs_para = m.cs_para
+    ", [$baseName, $pattern.'\_%', $maxParas])->n;
+};
+
+foreach ($alignment['names'] as $name => $entry) {
+    if (! $entry['applicable']) {
+        $log->count('name.skipped_low_confidence');
+        $log->unresolved('chapter_align_low_confidence', [
+            'book_name' => $name, 'confidence' => $entry['confidence'],
+            'chapters' => $entry['chapters'], 'wraps' => $entry['wraps'],
+            'detail' => '跨侧对齐置信不足,未加后缀,待补丁或 LLM 判定',
+        ]);
+
+        continue;
+    }
+    if (str_ends_with($name, '_A')) {
+        // 序言名不分章:它本就不对应正文段落,加后缀没有意义
+        $log->count('name.skipped_prologue');
+
+        continue;
+    }
+
+    $before = $pairedParagraphs($to, $name);
+
+    $changed = 0;
+    foreach ($entry['assignments'] as $a) {
+        $changed += DB::table($to)
+            ->where('book', $a['book'])
+            ->where('book_name', $name)
+            ->whereBetween('para', [$a['para_from'], $a['para_to']])
+            ->update(['book_name' => $name.'_'.$a['chapter']]);
+    }
+
+    $after = $pairedParagraphs($to, $name);
+
+    // 加对了后缀这个数应当上升或持平;下跌就是把真配对拆散了,整名回滚。
+    $tolerance = (int) max(5, $before * 0.02);
+    if ($after < $before - $tolerance) {
+        foreach ($entry['assignments'] as $a) {
+            DB::table($to)
+                ->where('book', $a['book'])
+                ->where('book_name', $name.'_'.$a['chapter'])
+                ->whereBetween('para', [$a['para_from'], $a['para_to']])
+                ->update(['book_name' => $name]);
+        }
+        $reverted++;
+        $log->warn(sprintf('%-8s 回滚:可信配对 %d → %d 段,跌幅超容差 %d', $name, $before, $after, $tolerance));
+        $log->unresolved('chapter_suffix_reverted', [
+            'book_name' => $name, 'paired_before' => $before, 'paired_after' => $after,
+            'chapters' => $entry['chapters'], 'confidence' => $entry['confidence'],
+            'detail' => '加章后缀后可信配对大幅下跌,已回滚;多半是并列的两本书被当成了顺序拼接,待补丁或 LLM 判定',
+        ]);
+        $log->count('name.reverted');
+
+        continue;
+    }
+
+    $applied++;
+    $rowsChanged += $changed;
+    $log->info(sprintf('%-8s %d 章,改名 %-6d 行,可信配对 %d → %d 段',
+        $name, $entry['chapters'], $changed, $before, $after));
+    $log->count('rows.renamed', $changed);
+}
+
+$log->info("加后缀的 book_name:{$applied} 个,共改名 {$rowsChanged} 行;因配对下跌回滚 {$reverted} 个");
+
+$log->info('建索引中…');
+DB::statement("create index on {$to} (book)");
+DB::statement("create index on {$to} (para)");
+DB::statement("create index on {$to} (book_name)");
+DB::statement("create index on {$to} (book_name, cs_para)");
+DB::statement("create index on {$to} (book, para, cs_para)");
+
+$log->finish();

+ 103 - 0
api-v13/scripts/related/backup.php

@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * 备份生产 related_paragraphs:库内快照表 + 库外 csv 存档 + 清单。
+ *
+ * 用法:
+ *   php scripts/related/backup.php                 # 表名自动带当天日期
+ *   php scripts/related/backup.php --tag=20260909  # 指定后缀
+ *   php scripts/related/backup.php --force         # 快照表已存在时覆盖
+ *
+ * 这是整个重建工程唯一允许写生产库的脚本,而且只做 CREATE TABLE AS,不改原表。
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+
+$source = 'related_paragraphs';
+$tag = $options['tag'] ?? date('Ymd');
+$snapshot = rp_assert_table("related_paragraphs_bak_$tag");
+$log = new RpLogger('backup', rp_report_dir());
+
+$log->info("源表:$source");
+$log->info("快照表:$snapshot");
+
+$sourceCount = DB::table($source)->count();
+$log->info("源表行数:$sourceCount");
+if ($sourceCount === 0) {
+    $log->error('源表为空,拒绝备份——这几乎一定是连错库了。');
+    $log->finish();
+    exit(1);
+}
+
+$exists = DB::selectOne('select to_regclass(?) as reg', [$snapshot])->reg !== null;
+if ($exists) {
+    if (! isset($options['force'])) {
+        $existing = DB::table($snapshot)->count();
+        $log->error("快照表已存在($existing 行)。要覆盖请加 --force。");
+        $log->finish();
+        exit(1);
+    }
+    $log->warn('快照表已存在,--force 生效,先 DROP。');
+    DB::statement("drop table $snapshot");
+}
+
+$log->info('建快照表中…');
+DB::statement("create table $snapshot as select * from $source");
+$snapshotCount = DB::table($snapshot)->count();
+$log->info("快照表行数:$snapshotCount");
+
+if ($snapshotCount !== $sourceCount) {
+    $log->error("行数不一致:源 $sourceCount vs 快照 $snapshotCount");
+    $log->finish();
+    exit(1);
+}
+
+// 快照表只用于比对,建最小索引即可(按 book/para 定位、按 book_name+cs_para 配对)。
+$log->info('建索引中…');
+DB::statement("create index on $snapshot (book, para)");
+DB::statement("create index on $snapshot (book_name, cs_para)");
+
+// 库外存档:库没了也能拿回数据。
+$archiveDir = rp_data_dir().'/backup';
+if (! is_dir($archiveDir)) {
+    mkdir($archiveDir, 0o755, true);
+}
+$csvPath = "$archiveDir/$snapshot.csv";
+$log->info("导出 csv:$csvPath");
+
+$handle = fopen($csvPath, 'w');
+fputcsv($handle, ['book', 'para', 'book_id', 'cs_para', 'book_name']);
+$rows = 0;
+DB::table($source)->orderBy('book')->orderBy('para')->orderBy('cs_para')->orderBy('id')
+    ->select('book', 'para', 'book_id', 'cs_para', 'book_name')
+    ->chunk(20000, function ($chunk) use ($handle, &$rows, $log) {
+        foreach ($chunk as $row) {
+            fputcsv($handle, [$row->book, $row->para, $row->book_id, $row->cs_para, $row->book_name]);
+            $rows++;
+        }
+        if ($rows % 200000 === 0) {
+            $log->info("  已导出 $rows 行");
+        }
+    });
+fclose($handle);
+$log->info("csv 行数:$rows");
+
+$manifest = [
+    'created_at' => date('c'),
+    'database' => DB::connection()->getDatabaseName(),
+    'source_table' => $source,
+    'snapshot_table' => $snapshot,
+    'rows' => $sourceCount,
+    'csv_path' => $csvPath,
+    'csv_sha256' => hash_file('sha256', $csvPath),
+    'csv_bytes' => filesize($csvPath),
+];
+rp_json_write("$archiveDir/$snapshot.manifest.json", $manifest);
+$log->info("清单:$archiveDir/$snapshot.manifest.json");
+$log->info('sha256: '.$manifest['csv_sha256']);
+
+$log->finish();

+ 3049 - 0
api-v13/scripts/related/baseline.json

@@ -0,0 +1,3049 @@
+{
+    "frozen_at": "2026-09-09T15:17:04+00:00",
+    "source_table": "related_paragraphs_bak_20260909",
+    "database": "visuddhinanda_20260311",
+    "purpose": "旧表的实测基线。clean_books 是零错误信号的书,重建后这些书一本都不许掉出来;detectors 是各探测器的旧表读数,用于回答「错误是否减少」。",
+    "clean_books": [
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        10,
+        12,
+        13,
+        14,
+        15,
+        16,
+        17,
+        18,
+        19,
+        20,
+        22,
+        23,
+        24,
+        25,
+        26,
+        27,
+        28,
+        29,
+        30,
+        31,
+        32,
+        33,
+        34,
+        35,
+        36,
+        37,
+        38,
+        39,
+        40,
+        41,
+        42,
+        43,
+        44,
+        45,
+        46,
+        47,
+        48,
+        49,
+        50,
+        51,
+        52,
+        53,
+        54,
+        55,
+        56,
+        57,
+        58,
+        59,
+        60,
+        61,
+        62,
+        63,
+        64,
+        65,
+        66,
+        67,
+        68,
+        74,
+        75,
+        77,
+        82,
+        83,
+        84,
+        85,
+        86,
+        87,
+        88,
+        89,
+        90,
+        91,
+        92,
+        93,
+        94,
+        95,
+        99,
+        101,
+        102,
+        105,
+        106,
+        110,
+        115,
+        117,
+        118,
+        129,
+        131,
+        133,
+        134,
+        135,
+        136,
+        141,
+        149,
+        155,
+        156,
+        157,
+        158,
+        159,
+        160,
+        161,
+        162,
+        163,
+        164,
+        165,
+        166,
+        167,
+        168,
+        169,
+        170,
+        171,
+        177,
+        180,
+        181,
+        187,
+        188,
+        196,
+        197,
+        198,
+        204,
+        212,
+        213,
+        214,
+        215,
+        216,
+        217
+    ],
+    "detectors": {
+        "E1_cs_garbage": {
+            "rows": 1242,
+            "books": 24
+        },
+        "E2_chapter_wrap": {
+            "wrap_points": 395,
+            "books": 64
+        },
+        "E3_kn10_missing": {
+            "kn10_rows": 0,
+            "kn10_a_rows": 16926,
+            "kn10_b_rows": 12489
+        },
+        "E4_empty_book_name": {
+            "rows": 112965,
+            "books": 60
+        },
+        "E5_book_id_zero": {
+            "rows": 354,
+            "books": 201
+        },
+        "E6_coverage_gap": {
+            "segments": 3466,
+            "books": 45
+        },
+        "E7_abbrev_interval_lost": {
+            "marker_segments": 1519,
+            "books": 44,
+            "segments_without_rows": 1292,
+            "segments_with_garbage": 225
+        },
+        "E8_flat_pollution": {
+            "groups": 1,
+            "rows": 1499
+        },
+        "E9_no_marker_books": {
+            "books": 16,
+            "book_list": [
+                8,
+                15,
+                16,
+                25,
+                37,
+                39,
+                40,
+                41,
+                42,
+                44,
+                45,
+                47,
+                48,
+                56,
+                61,
+                129
+            ]
+        },
+        "E10_selfmade_names": {
+            "nk_rows": 986,
+            "subo_rows": 4258,
+            "dict_rows": 7041
+        },
+        "D_continuity": {
+            "broken_groups": 9026,
+            "books": 69,
+            "extra_segments": 30204
+        },
+        "D_mirror_alignment": {
+            "deviations": 0,
+            "detail": []
+        },
+        "D_interval_expansion": {
+            "interval_markers": 3615,
+            "mismatched_markers": 1611,
+            "empty_markers": 1611
+        },
+        "D_pairing": {
+            "keys": 41525,
+            "keys_cross_book": 27853,
+            "rows_paired": 432110,
+            "rows_paired_trusted": 177016,
+            "rows_total": 507795,
+            "mean_books_per_key": 2.079,
+            "keys_bloated": 6671,
+            "keys_bloated_bad": 1413,
+            "worst_paras_in_one_book": 1578
+        }
+    },
+    "scorecard": [
+        {
+            "book": 1,
+            "rows": 986,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 3,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 3
+        },
+        {
+            "book": 2,
+            "rows": 845,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 845,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 3,
+            "rows": 316,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 316,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 4,
+            "rows": 597,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 597,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 5,
+            "rows": 1025,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1025,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 6,
+            "rows": 302,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 302,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 7,
+            "rows": 526,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 526,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 8,
+            "rows": 2458,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2458,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 9,
+            "rows": 3109,
+            "names": 1,
+            "garbage_rows": 31,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 32
+        },
+        {
+            "book": 10,
+            "rows": 1320,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 11,
+            "rows": 2938,
+            "names": 1,
+            "garbage_rows": 96,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 2,
+            "gap_segments": 3,
+            "flat_groups": 0,
+            "signals": 101
+        },
+        {
+            "book": 12,
+            "rows": 847,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 847,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 13,
+            "rows": 3262,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 3262,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 14,
+            "rows": 3486,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 3486,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 15,
+            "rows": 2980,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2980,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 16,
+            "rows": 3401,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 3401,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 17,
+            "rows": 4055,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 4055,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 18,
+            "rows": 1579,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1579,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 19,
+            "rows": 2493,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2493,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 20,
+            "rows": 318,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 318,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 21,
+            "rows": 3963,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 31,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 22,
+            "rows": 6144,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 6144,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 23,
+            "rows": 1498,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 24,
+            "rows": 442,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 25,
+            "rows": 249,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 249,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 26,
+            "rows": 1960,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1960,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 27,
+            "rows": 1347,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1347,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 28,
+            "rows": 243,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 243,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 29,
+            "rows": 1333,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1333,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 30,
+            "rows": 1283,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1283,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 31,
+            "rows": 876,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 876,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 32,
+            "rows": 266,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 266,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 33,
+            "rows": 545,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 545,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 34,
+            "rows": 552,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 552,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 35,
+            "rows": 1847,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1847,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 36,
+            "rows": 2457,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2457,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 37,
+            "rows": 433,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 433,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 38,
+            "rows": 2613,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2613,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 39,
+            "rows": 349,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 349,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 40,
+            "rows": 688,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 688,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 41,
+            "rows": 1256,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 1256,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 42,
+            "rows": 907,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 907,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 43,
+            "rows": 1554,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 1554,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 44,
+            "rows": 296,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 296,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 45,
+            "rows": 503,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 503,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 46,
+            "rows": 1240,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 47,
+            "rows": 1640,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 1640,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 48,
+            "rows": 1095,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 1095,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 49,
+            "rows": 83,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 83,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 50,
+            "rows": 494,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 494,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 51,
+            "rows": 3057,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 3057,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 52,
+            "rows": 1703,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 1703,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 53,
+            "rows": 709,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 709,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 54,
+            "rows": 1642,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 1642,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 55,
+            "rows": 118,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 118,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 56,
+            "rows": 491,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 491,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 57,
+            "rows": 364,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 364,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 58,
+            "rows": 1649,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 1649,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 59,
+            "rows": 9907,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 9907,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 60,
+            "rows": 501,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 501,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 61,
+            "rows": 152,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 152,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 62,
+            "rows": 971,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 971,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 63,
+            "rows": 15944,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 15944,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 64,
+            "rows": 2240,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 65,
+            "rows": 2192,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 66,
+            "rows": 1613,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 67,
+            "rows": 1851,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 68,
+            "rows": 2701,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2701,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 69,
+            "rows": 4241,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 16,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 16
+        },
+        {
+            "book": 70,
+            "rows": 6004,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 9,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 9
+        },
+        {
+            "book": 71,
+            "rows": 8046,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 20,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 20
+        },
+        {
+            "book": 72,
+            "rows": 5169,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 19,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 19
+        },
+        {
+            "book": 73,
+            "rows": 2436,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 2
+        },
+        {
+            "book": 74,
+            "rows": 3427,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 75,
+            "rows": 673,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 76,
+            "rows": 561,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 77,
+            "rows": 3460,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 78,
+            "rows": 4774,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 4,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 4
+        },
+        {
+            "book": 79,
+            "rows": 3859,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 2
+        },
+        {
+            "book": 80,
+            "rows": 5586,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 81,
+            "rows": 4301,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 4,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 4
+        },
+        {
+            "book": 82,
+            "rows": 3141,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 83,
+            "rows": 1889,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 84,
+            "rows": 957,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 85,
+            "rows": 485,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 86,
+            "rows": 1938,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 87,
+            "rows": 3439,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 88,
+            "rows": 16266,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 89,
+            "rows": 2377,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 1,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 90,
+            "rows": 14831,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 91,
+            "rows": 2604,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 92,
+            "rows": 1504,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 93,
+            "rows": 1074,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 94,
+            "rows": 1559,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 95,
+            "rows": 1910,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 96,
+            "rows": 3551,
+            "names": 1,
+            "garbage_rows": 3,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 2,
+            "gap_segments": 30,
+            "flat_groups": 0,
+            "signals": 36
+        },
+        {
+            "book": 97,
+            "rows": 2423,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 2,
+            "gap_segments": 9,
+            "flat_groups": 0,
+            "signals": 11
+        },
+        {
+            "book": 98,
+            "rows": 17589,
+            "names": 5,
+            "garbage_rows": 40,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 12,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 52
+        },
+        {
+            "book": 99,
+            "rows": 2078,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 100,
+            "rows": 3738,
+            "names": 3,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 2,
+            "gap_segments": 4,
+            "flat_groups": 0,
+            "signals": 6
+        },
+        {
+            "book": 101,
+            "rows": 1162,
+            "names": 3,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 102,
+            "rows": 950,
+            "names": 4,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 103,
+            "rows": 1976,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 1,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 104,
+            "rows": 1731,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 4,
+            "flat_groups": 0,
+            "signals": 5
+        },
+        {
+            "book": 105,
+            "rows": 1131,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 106,
+            "rows": 4548,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 107,
+            "rows": 4096,
+            "names": 2,
+            "garbage_rows": 47,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 22,
+            "abbrev_lost": 22,
+            "gap_segments": 48,
+            "flat_groups": 0,
+            "signals": 139
+        },
+        {
+            "book": 108,
+            "rows": 4194,
+            "names": 1,
+            "garbage_rows": 80,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 25,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 105
+        },
+        {
+            "book": 109,
+            "rows": 2136,
+            "names": 1,
+            "garbage_rows": 80,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 6,
+            "gap_segments": 10,
+            "flat_groups": 0,
+            "signals": 98
+        },
+        {
+            "book": 110,
+            "rows": 3117,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 111,
+            "rows": 2997,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 112,
+            "rows": 4892,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 5,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 5
+        },
+        {
+            "book": 113,
+            "rows": 7714,
+            "names": 1,
+            "garbage_rows": 21,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 5,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 26
+        },
+        {
+            "book": 114,
+            "rows": 5079,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 0,
+            "empty_name_rows": 0,
+            "wrap_points": 4,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 4
+        },
+        {
+            "book": 115,
+            "rows": 3688,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 116,
+            "rows": 1235,
+            "names": 1,
+            "garbage_rows": 26,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 4,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 30
+        },
+        {
+            "book": 117,
+            "rows": 6463,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 118,
+            "rows": 1833,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 119,
+            "rows": 765,
+            "names": 1,
+            "garbage_rows": 18,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 2,
+            "flat_groups": 0,
+            "signals": 21
+        },
+        {
+            "book": 120,
+            "rows": 2718,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 3,
+            "abbrev_lost": 1,
+            "gap_segments": 6,
+            "flat_groups": 0,
+            "signals": 10
+        },
+        {
+            "book": 121,
+            "rows": 1096,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 122,
+            "rows": 5231,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 123,
+            "rows": 1688,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 124,
+            "rows": 1766,
+            "names": 1,
+            "garbage_rows": 7,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 7
+        },
+        {
+            "book": 125,
+            "rows": 2505,
+            "names": 1,
+            "garbage_rows": 1,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 114,
+            "gap_segments": 306,
+            "flat_groups": 0,
+            "signals": 421
+        },
+        {
+            "book": 126,
+            "rows": 3973,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 36,
+            "gap_segments": 87,
+            "flat_groups": 0,
+            "signals": 124
+        },
+        {
+            "book": 127,
+            "rows": 3281,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 46,
+            "gap_segments": 98,
+            "flat_groups": 0,
+            "signals": 145
+        },
+        {
+            "book": 128,
+            "rows": 5390,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 2,
+            "gap_segments": 22,
+            "flat_groups": 0,
+            "signals": 24
+        },
+        {
+            "book": 129,
+            "rows": 6605,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 130,
+            "rows": 2906,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 2,
+            "gap_segments": 6,
+            "flat_groups": 0,
+            "signals": 9
+        },
+        {
+            "book": 131,
+            "rows": 1369,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 132,
+            "rows": 1105,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 2,
+            "flat_groups": 0,
+            "signals": 3
+        },
+        {
+            "book": 133,
+            "rows": 1480,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 134,
+            "rows": 1228,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 135,
+            "rows": 2850,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 136,
+            "rows": 1862,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 137,
+            "rows": 2840,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 9,
+            "gap_segments": 52,
+            "flat_groups": 0,
+            "signals": 61
+        },
+        {
+            "book": 138,
+            "rows": 2805,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 26,
+            "gap_segments": 218,
+            "flat_groups": 0,
+            "signals": 244
+        },
+        {
+            "book": 139,
+            "rows": 1349,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 32,
+            "gap_segments": 147,
+            "flat_groups": 0,
+            "signals": 179
+        },
+        {
+            "book": 140,
+            "rows": 944,
+            "names": 1,
+            "garbage_rows": 6,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 6,
+            "gap_segments": 18,
+            "flat_groups": 0,
+            "signals": 30
+        },
+        {
+            "book": 141,
+            "rows": 670,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 142,
+            "rows": 717,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 1,
+            "flat_groups": 0,
+            "signals": 2
+        },
+        {
+            "book": 143,
+            "rows": 14646,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 41,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 41
+        },
+        {
+            "book": 144,
+            "rows": 10673,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 17,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 17
+        },
+        {
+            "book": 145,
+            "rows": 3282,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 28,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 28
+        },
+        {
+            "book": 146,
+            "rows": 1199,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 2
+        },
+        {
+            "book": 147,
+            "rows": 11528,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 5,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 5
+        },
+        {
+            "book": 148,
+            "rows": 10506,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 15,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 15
+        },
+        {
+            "book": 149,
+            "rows": 2927,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 150,
+            "rows": 2771,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 151,
+            "rows": 2044,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 3,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 3
+        },
+        {
+            "book": 152,
+            "rows": 2493,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 22,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 22
+        },
+        {
+            "book": 153,
+            "rows": 1624,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 154,
+            "rows": 276,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 6,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 6
+        },
+        {
+            "book": 155,
+            "rows": 1217,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 156,
+            "rows": 1394,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 157,
+            "rows": 965,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 158,
+            "rows": 1194,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 159,
+            "rows": 4051,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 160,
+            "rows": 3279,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 161,
+            "rows": 2655,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 162,
+            "rows": 4669,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 163,
+            "rows": 1785,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 164,
+            "rows": 1797,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 165,
+            "rows": 1690,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 166,
+            "rows": 1463,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 167,
+            "rows": 3498,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 168,
+            "rows": 1427,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 169,
+            "rows": 3165,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 170,
+            "rows": 2225,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 171,
+            "rows": 5900,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 172,
+            "rows": 1366,
+            "names": 1,
+            "garbage_rows": 7,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 1,
+            "gap_segments": 4,
+            "flat_groups": 0,
+            "signals": 14
+        },
+        {
+            "book": 173,
+            "rows": 2315,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 7,
+            "gap_segments": 20,
+            "flat_groups": 0,
+            "signals": 28
+        },
+        {
+            "book": 174,
+            "rows": 10905,
+            "names": 5,
+            "garbage_rows": 39,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 10,
+            "abbrev_lost": 2,
+            "gap_segments": 6,
+            "flat_groups": 0,
+            "signals": 57
+        },
+        {
+            "book": 175,
+            "rows": 1275,
+            "names": 1,
+            "garbage_rows": 9,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 11
+        },
+        {
+            "book": 176,
+            "rows": 11901,
+            "names": 5,
+            "garbage_rows": 43,
+            "no_book_id_rows": 3,
+            "empty_name_rows": 0,
+            "wrap_points": 10,
+            "abbrev_lost": 0,
+            "gap_segments": 3,
+            "flat_groups": 0,
+            "signals": 56
+        },
+        {
+            "book": 177,
+            "rows": 15499,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 10695,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 178,
+            "rows": 1838,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 17,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 17
+        },
+        {
+            "book": 179,
+            "rows": 2403,
+            "names": 2,
+            "garbage_rows": 55,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 418,
+            "gap_segments": 805,
+            "flat_groups": 0,
+            "signals": 1279
+        },
+        {
+            "book": 180,
+            "rows": 2826,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 2826,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 181,
+            "rows": 1451,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 182,
+            "rows": 3328,
+            "names": 3,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 10,
+            "gap_segments": 46,
+            "flat_groups": 0,
+            "signals": 56
+        },
+        {
+            "book": 183,
+            "rows": 2094,
+            "names": 3,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 10,
+            "gap_segments": 45,
+            "flat_groups": 0,
+            "signals": 57
+        },
+        {
+            "book": 184,
+            "rows": 6356,
+            "names": 4,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 4,
+            "flat_groups": 0,
+            "signals": 5
+        },
+        {
+            "book": 185,
+            "rows": 1588,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 17,
+            "gap_segments": 54,
+            "flat_groups": 0,
+            "signals": 71
+        },
+        {
+            "book": 186,
+            "rows": 1509,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 13,
+            "flat_groups": 0,
+            "signals": 14
+        },
+        {
+            "book": 187,
+            "rows": 1132,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 188,
+            "rows": 1781,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 189,
+            "rows": 1572,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 10,
+            "gap_segments": 37,
+            "flat_groups": 0,
+            "signals": 47
+        },
+        {
+            "book": 190,
+            "rows": 764,
+            "names": 1,
+            "garbage_rows": 1,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 2
+        },
+        {
+            "book": 191,
+            "rows": 1670,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 192,
+            "rows": 2397,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 3,
+            "gap_segments": 3,
+            "flat_groups": 0,
+            "signals": 8
+        },
+        {
+            "book": 193,
+            "rows": 936,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 3,
+            "flat_groups": 0,
+            "signals": 4
+        },
+        {
+            "book": 194,
+            "rows": 856,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 1,
+            "gap_segments": 2,
+            "flat_groups": 0,
+            "signals": 3
+        },
+        {
+            "book": 195,
+            "rows": 1709,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 196,
+            "rows": 1328,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 197,
+            "rows": 3276,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 198,
+            "rows": 1928,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 199,
+            "rows": 2837,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 7,
+            "gap_segments": 28,
+            "flat_groups": 0,
+            "signals": 35
+        },
+        {
+            "book": 200,
+            "rows": 13281,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 201,
+            "rows": 4584,
+            "names": 2,
+            "garbage_rows": 452,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 256,
+            "gap_segments": 566,
+            "flat_groups": 0,
+            "signals": 1275
+        },
+        {
+            "book": 202,
+            "rows": 2989,
+            "names": 4,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 3,
+            "abbrev_lost": 10,
+            "gap_segments": 55,
+            "flat_groups": 0,
+            "signals": 68
+        },
+        {
+            "book": 203,
+            "rows": 3404,
+            "names": 2,
+            "garbage_rows": 81,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 84,
+            "gap_segments": 294,
+            "flat_groups": 0,
+            "signals": 460
+        },
+        {
+            "book": 204,
+            "rows": 1659,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 205,
+            "rows": 1926,
+            "names": 1,
+            "garbage_rows": 5,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 3,
+            "gap_segments": 4,
+            "flat_groups": 0,
+            "signals": 14
+        },
+        {
+            "book": 206,
+            "rows": 2862,
+            "names": 4,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 3,
+            "abbrev_lost": 4,
+            "gap_segments": 10,
+            "flat_groups": 0,
+            "signals": 17
+        },
+        {
+            "book": 207,
+            "rows": 2713,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 12,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 1,
+            "signals": 13
+        },
+        {
+            "book": 208,
+            "rows": 1673,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 1
+        },
+        {
+            "book": 209,
+            "rows": 2562,
+            "names": 5,
+            "garbage_rows": 70,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 1,
+            "abbrev_lost": 85,
+            "gap_segments": 255,
+            "flat_groups": 0,
+            "signals": 411
+        },
+        {
+            "book": 210,
+            "rows": 3901,
+            "names": 5,
+            "garbage_rows": 24,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 4,
+            "abbrev_lost": 46,
+            "gap_segments": 132,
+            "flat_groups": 0,
+            "signals": 206
+        },
+        {
+            "book": 211,
+            "rows": 2413,
+            "names": 2,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 2,
+            "abbrev_lost": 1,
+            "gap_segments": 1,
+            "flat_groups": 0,
+            "signals": 4
+        },
+        {
+            "book": 212,
+            "rows": 2517,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 1,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 213,
+            "rows": 2477,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 214,
+            "rows": 3690,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 215,
+            "rows": 2759,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 216,
+            "rows": 2821,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        },
+        {
+            "book": 217,
+            "rows": 3645,
+            "names": 1,
+            "garbage_rows": 0,
+            "no_book_id_rows": 2,
+            "empty_name_rows": 0,
+            "wrap_points": 0,
+            "abbrev_lost": 0,
+            "gap_segments": 0,
+            "flat_groups": 0,
+            "signals": 0
+        }
+    ]
+}

+ 6374 - 0
api-v13/scripts/related/book_config.json

@@ -0,0 +1,6374 @@
+{
+    "generated_at": "2026-09-09T15:01:15+00:00",
+    "baseline_table": "related_paragraphs_bak_20260909",
+    "purpose": "每本 VRI 文件的类型与书名分段。导出器优先用 wbw 现场证据,此表只在文件本身没有书名信息时兜底。overrides 是人工修正区,重跑不覆盖。",
+    "books": {
+        "1": {
+            "max_paragraph": 981,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 1,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "namakkāra",
+                        "añña",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "namakkārapāḷi"
+                    ]
+                },
+                {
+                    "book_id": 2,
+                    "from_paragraph": 159,
+                    "type": "tika",
+                    "tags": [
+                        "namakkāraṭīkā",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "añña",
+                        "ṭīkā",
+                        "namakkāra"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 981,
+                    "book_name": "NK"
+                }
+            ]
+        },
+        "2": {
+            "max_paragraph": 845,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 3,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "mahāpaṇāmapāṭha"
+                    ]
+                },
+                {
+                    "book_id": 4,
+                    "from_paragraph": 428,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "mahāpaṇāmapāṭha",
+                        "buddha-vandanā ganthasaṅgaha"
+                    ]
+                },
+                {
+                    "book_id": 5,
+                    "from_paragraph": 479,
+                    "type": "unknown",
+                    "tags": [
+                        "mahāpaṇāmapāṭha",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 845,
+                    "book_name": ""
+                }
+            ]
+        },
+        "3": {
+            "max_paragraph": 316,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 6,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "lakkhaṇāto",
+                        "buddha-vandanā ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 316,
+                    "book_name": ""
+                }
+            ]
+        },
+        "4": {
+            "max_paragraph": 597,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 7,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "suttavandanā",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 597,
+                    "book_name": ""
+                }
+            ]
+        },
+        "5": {
+            "max_paragraph": 1025,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 8,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "jinālaṅkāra",
+                        "añña",
+                        "buddha-vandanā ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1025,
+                    "book_name": ""
+                }
+            ]
+        },
+        "6": {
+            "max_paragraph": 302,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 9,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "kamalāñjali"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 302,
+                    "book_name": ""
+                }
+            ]
+        },
+        "7": {
+            "max_paragraph": 526,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 10,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "pajjamadhu",
+                        "buddha-vandanā ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 526,
+                    "book_name": ""
+                }
+            ]
+        },
+        "8": {
+            "max_paragraph": 2458,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 11,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "buddha-vandanā ganthasaṅgaha",
+                        "buddhaguṇagāthāvalī",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2458,
+                    "book_name": ""
+                }
+            ]
+        },
+        "9": {
+            "max_paragraph": 2714,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 12,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "abhidhānappadīpikāṭīkā",
+                        "nirutti",
+                        "abhidhānappadīpikā",
+                        "byākaraṇa ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2714,
+                    "book_name": "dict"
+                }
+            ]
+        },
+        "10": {
+            "max_paragraph": 1320,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 13,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "byākaraṇa ganthasaṅgaha",
+                        "subodhālaṅkāra",
+                        "nirutti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1320,
+                    "book_name": "subo"
+                }
+            ]
+        },
+        "11": {
+            "max_paragraph": 2885,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 14,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "subodhālaṅkāra",
+                        "nirutti",
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña",
+                        "subodhālaṅkāraṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2885,
+                    "book_name": "subo"
+                }
+            ]
+        },
+        "12": {
+            "max_paragraph": 847,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 15,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "avatāra",
+                        "nirutti",
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña",
+                        "bālāvatāra"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 847,
+                    "book_name": ""
+                }
+            ]
+        },
+        "13": {
+            "max_paragraph": 3262,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 16,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "moggallānasuttapāṭha",
+                        "añña",
+                        "byākaraṇa ganthasaṅgaha",
+                        "nirutti"
+                    ]
+                },
+                {
+                    "book_id": 17,
+                    "from_paragraph": 1105,
+                    "type": "unknown",
+                    "tags": [
+                        "moggallānabyākaraṇa",
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña",
+                        "nirutti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3262,
+                    "book_name": ""
+                }
+            ]
+        },
+        "14": {
+            "max_paragraph": 3486,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 18,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "byākaraṇa ganthasaṅgaha",
+                        "kaccāyanabyākaraṇa",
+                        "nirutti",
+                        "añña"
+                    ]
+                },
+                {
+                    "book_id": 19,
+                    "from_paragraph": 715,
+                    "type": "unknown",
+                    "tags": [
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña",
+                        "nirutti",
+                        "kaccāyanabyākaraṇa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3486,
+                    "book_name": ""
+                }
+            ]
+        },
+        "15": {
+            "max_paragraph": 2980,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 20,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "padamālā",
+                        "saddanītippakaraṇa",
+                        "nirutti",
+                        "byākaraṇa ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2980,
+                    "book_name": ""
+                }
+            ]
+        },
+        "16": {
+            "max_paragraph": 3401,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 21,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "dhātumālā",
+                        "saddanītippakaraṇa",
+                        "nirutti",
+                        "byākaraṇa ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3401,
+                    "book_name": ""
+                }
+            ]
+        },
+        "17": {
+            "max_paragraph": 4055,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 22,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "padarūpasiddhi",
+                        "byākaraṇa ganthasaṅgaha",
+                        "nirutti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4055,
+                    "book_name": ""
+                }
+            ]
+        },
+        "18": {
+            "max_paragraph": 1579,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 23,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "moggallāna pañcikā ṭīkā",
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña",
+                        "nirutti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1579,
+                    "book_name": ""
+                }
+            ]
+        },
+        "19": {
+            "max_paragraph": 2493,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 24,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "nirutti",
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña",
+                        "payogasiddhipāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2493,
+                    "book_name": ""
+                }
+            ]
+        },
+        "20": {
+            "max_paragraph": 318,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 25,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "vuttodaya",
+                        "nirutti",
+                        "byākaraṇa ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 318,
+                    "book_name": ""
+                }
+            ]
+        },
+        "21": {
+            "max_paragraph": 3963,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 26,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "byākaraṇa ganthasaṅgaha",
+                        "abhidhānappadīpikā",
+                        "nirutti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3932,
+                    "book_name": "dict"
+                },
+                {
+                    "para_from": 3933,
+                    "para_to": 3963,
+                    "book_name": ""
+                }
+            ]
+        },
+        "22": {
+            "max_paragraph": 6144,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 27,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "niruttidīpanīpāṭha",
+                        "añña",
+                        "nirutti",
+                        "leḍī sayādo"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 6144,
+                    "book_name": ""
+                }
+            ]
+        },
+        "23": {
+            "max_paragraph": 1498,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 28,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "paramatthadīpanī",
+                        "abhidhammatthasaṅgaha",
+                        "abhidhamma",
+                        "leḍī sayādo",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1498,
+                    "book_name": "abhi9"
+                }
+            ]
+        },
+        "24": {
+            "max_paragraph": 434,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 29,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "abhidhamma",
+                        "abhidhammatthasaṅgaha",
+                        "anudīpanīpāṭha",
+                        "leḍī sayādo",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 434,
+                    "book_name": "abhi9"
+                }
+            ]
+        },
+        "25": {
+            "max_paragraph": 249,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 30,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "paṭṭhānuddesa dīpanīpāṭha",
+                        "abhidhamma",
+                        "leḍī sayādo",
+                        "añña",
+                        "paṭṭhāna"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 249,
+                    "book_name": ""
+                }
+            ]
+        },
+        "26": {
+            "max_paragraph": 1960,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 31,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "dīpanī",
+                        "añña",
+                        "nīti-ganthasaṅgaha",
+                        "caturārakkhadīpanī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1960,
+                    "book_name": ""
+                }
+            ]
+        },
+        "27": {
+            "max_paragraph": 1347,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 32,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "kavidappaṇanīti",
+                        "nīti-ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1347,
+                    "book_name": ""
+                }
+            ]
+        },
+        "28": {
+            "max_paragraph": 243,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 33,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "nītimañjarī",
+                        "nīti-ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 243,
+                    "book_name": ""
+                }
+            ]
+        },
+        "29": {
+            "max_paragraph": 1333,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 34,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "dhammanīti",
+                        "nīti-ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1333,
+                    "book_name": ""
+                }
+            ]
+        },
+        "30": {
+            "max_paragraph": 1283,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 35,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "nīti-ganthasaṅgaha",
+                        "mahārahanīti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1283,
+                    "book_name": ""
+                }
+            ]
+        },
+        "31": {
+            "max_paragraph": 876,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 36,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "lokanīti",
+                        "nīti-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 876,
+                    "book_name": ""
+                }
+            ]
+        },
+        "32": {
+            "max_paragraph": 266,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 37,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "suttantanīti",
+                        "nīti-ganthasaṅgaha"
+                    ]
+                },
+                {
+                    "book_id": 38,
+                    "from_paragraph": 134,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "nīti-ganthasaṅgaha",
+                        "suttantanīti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 266,
+                    "book_name": ""
+                }
+            ]
+        },
+        "33": {
+            "max_paragraph": 545,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 39,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "sūrassatīnīti",
+                        "nīti-ganthasaṅgaha",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 545,
+                    "book_name": ""
+                }
+            ]
+        },
+        "34": {
+            "max_paragraph": 552,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 40,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "nīti-ganthasaṅgaha",
+                        "cāṇakyanītipāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 552,
+                    "book_name": ""
+                }
+            ]
+        },
+        "35": {
+            "max_paragraph": 1847,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 41,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "naradakkhadīpanī",
+                        "añña",
+                        "nīti-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1847,
+                    "book_name": ""
+                }
+            ]
+        },
+        "36": {
+            "max_paragraph": 2457,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 42,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "rasavāhinī",
+                        "añña",
+                        "pakiṇṇaka-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2457,
+                    "book_name": ""
+                }
+            ]
+        },
+        "37": {
+            "max_paragraph": 433,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 43,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "sīmavisodhanī",
+                        "pakiṇṇaka",
+                        "pakiṇṇaka-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 433,
+                    "book_name": ""
+                }
+            ]
+        },
+        "38": {
+            "max_paragraph": 2613,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 44,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "pakiṇṇaka-ganthasaṅgaha",
+                        "vessantarāgīti",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2613,
+                    "book_name": ""
+                }
+            ]
+        },
+        "39": {
+            "max_paragraph": 349,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 45,
+                    "from_paragraph": 3,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "dīghanikāya",
+                        "sutta",
+                        "saṅgayana-puccha vissajjanā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 349,
+                    "book_name": ""
+                }
+            ]
+        },
+        "40": {
+            "max_paragraph": 688,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 46,
+                    "from_paragraph": 3,
+                    "type": "unknown",
+                    "tags": [
+                        "sutta",
+                        "saṅgayana-puccha vissajjanā",
+                        "añña",
+                        "majjhimanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 688,
+                    "book_name": ""
+                }
+            ]
+        },
+        "41": {
+            "max_paragraph": 1256,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 47,
+                    "from_paragraph": 3,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "saṅgayana-puccha vissajjanā",
+                        "saṃyuttanikāya",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1256,
+                    "book_name": ""
+                }
+            ]
+        },
+        "42": {
+            "max_paragraph": 907,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 48,
+                    "from_paragraph": 3,
+                    "type": "unknown",
+                    "tags": [
+                        "saṅgayana-puccha vissajjanā",
+                        "añña",
+                        "sutta",
+                        "aṅguttaranikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 907,
+                    "book_name": ""
+                }
+            ]
+        },
+        "43": {
+            "max_paragraph": 1554,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 49,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "vinaya",
+                        "saṅgayana-puccha vissajjanā",
+                        "añña",
+                        "vinayapiṭaka"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1554,
+                    "book_name": ""
+                }
+            ]
+        },
+        "44": {
+            "max_paragraph": 296,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 50,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "abhidhammapiṭaka",
+                        "abhidhamma",
+                        "añña",
+                        "saṅgayana-puccha vissajjanā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 296,
+                    "book_name": ""
+                }
+            ]
+        },
+        "45": {
+            "max_paragraph": 503,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 51,
+                    "from_paragraph": 2,
+                    "type": "atthakatha",
+                    "tags": [
+                        "saṅgayana-puccha vissajjanā",
+                        "añña",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 503,
+                    "book_name": ""
+                }
+            ]
+        },
+        "46": {
+            "max_paragraph": 1240,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 52,
+                    "from_paragraph": 1,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "milidaṭīkā",
+                        "sihaḷa-ganthasaṅgaha",
+                        "milindapañha",
+                        "añña",
+                        "khuddakanikāya",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1240,
+                    "book_name": "kn18"
+                }
+            ]
+        },
+        "47": {
+            "max_paragraph": 1640,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 53,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "padamañjarī",
+                        "nirutti",
+                        "sihaḷa-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1640,
+                    "book_name": ""
+                }
+            ]
+        },
+        "48": {
+            "max_paragraph": 1095,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 54,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "nirutti",
+                        "padasādhana"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1095,
+                    "book_name": ""
+                }
+            ]
+        },
+        "49": {
+            "max_paragraph": 83,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 55,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "nirutti",
+                        "saddabindupakaraṇa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 83,
+                    "book_name": ""
+                }
+            ]
+        },
+        "50": {
+            "max_paragraph": 494,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 56,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "kaccāyanadhātumañjūsā",
+                        "añña",
+                        "nirutti",
+                        "sihaḷa-ganthasaṅgaha",
+                        "kaccāyana"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 494,
+                    "book_name": ""
+                }
+            ]
+        },
+        "51": {
+            "max_paragraph": 3057,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 57,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "samantakūṭavaṇṇanā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3057,
+                    "book_name": ""
+                }
+            ]
+        },
+        "52": {
+            "max_paragraph": 1703,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 58,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "moggallāna vuttivivaraṇapañcikā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1703,
+                    "book_name": ""
+                }
+            ]
+        },
+        "53": {
+            "max_paragraph": 709,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 59,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "sihaḷa-ganthasaṅgaha",
+                        "thupavaṃsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 709,
+                    "book_name": ""
+                }
+            ]
+        },
+        "54": {
+            "max_paragraph": 1642,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 60,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "dāṭhāvaṃsa",
+                        "añña",
+                        "sihaḷa-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1642,
+                    "book_name": ""
+                }
+            ]
+        },
+        "55": {
+            "max_paragraph": 118,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 61,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "dhātupāṭha vilāsiniyā",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 118,
+                    "book_name": ""
+                }
+            ]
+        },
+        "56": {
+            "max_paragraph": 491,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 62,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "dhātuvaṃsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 491,
+                    "book_name": ""
+                }
+            ]
+        },
+        "57": {
+            "max_paragraph": 364,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 63,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "hatthavanagallavihāravaṃsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 364,
+                    "book_name": ""
+                }
+            ]
+        },
+        "58": {
+            "max_paragraph": 1649,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 64,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "jinacaritaya",
+                        "añña",
+                        "sihaḷa-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1649,
+                    "book_name": ""
+                }
+            ]
+        },
+        "59": {
+            "max_paragraph": 9907,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 65,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "sihaḷa-ganthasaṅgaha",
+                        "jinavaṃsadīpa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 9907,
+                    "book_name": ""
+                }
+            ]
+        },
+        "60": {
+            "max_paragraph": 501,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 66,
+                    "from_paragraph": 1,
+                    "type": "unknown",
+                    "tags": [
+                        "sihaḷa-ganthasaṅgaha",
+                        "añña",
+                        "telakaṭāhagāthā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 501,
+                    "book_name": ""
+                }
+            ]
+        },
+        "61": {
+            "max_paragraph": 152,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 67,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "cūḷaganthavaṃsapāḷi",
+                        "vaṃsa ganthasaṅgaha",
+                        "añña",
+                        "vaṃsa-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 152,
+                    "book_name": ""
+                }
+            ]
+        },
+        "62": {
+            "max_paragraph": 971,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 68,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "añña",
+                        "vaṃsa ganthasaṅgaha",
+                        "vaṃsa-ganthasaṅgaha",
+                        "sāsanavaṃsappadīpikā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 971,
+                    "book_name": ""
+                }
+            ]
+        },
+        "63": {
+            "max_paragraph": 15944,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 69,
+                    "from_paragraph": 2,
+                    "type": "unknown",
+                    "tags": [
+                        "mahāvaṃsapāḷi",
+                        "vaṃsa ganthasaṅgaha",
+                        "añña",
+                        "vaṃsa-ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 15944,
+                    "book_name": ""
+                }
+            ]
+        },
+        "64": {
+            "max_paragraph": 2240,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 70,
+                    "from_paragraph": 2,
+                    "type": "atthakatha",
+                    "tags": [
+                        "visuddhimagga",
+                        "aṭṭhakathā",
+                        "paṭhamo bhāgo",
+                        "añña"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2240,
+                    "book_name": "vism"
+                }
+            ]
+        },
+        "65": {
+            "max_paragraph": 2192,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 71,
+                    "from_paragraph": 2,
+                    "type": "atthakatha",
+                    "tags": [
+                        "visuddhimagga",
+                        "dutiyo bhāgo",
+                        "añña",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2192,
+                    "book_name": "vism"
+                }
+            ]
+        },
+        "66": {
+            "max_paragraph": 1613,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 72,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "paṭhamo bhāgo",
+                        "mahāṭīkā",
+                        "añña",
+                        "visuddhimagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1613,
+                    "book_name": "vism"
+                }
+            ]
+        },
+        "67": {
+            "max_paragraph": 1851,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 73,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "añña",
+                        "mahāṭīkā",
+                        "dutiyo bhāgo",
+                        "visuddhimagga",
+                        "ṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1851,
+                    "book_name": "vism"
+                }
+            ]
+        },
+        "68": {
+            "max_paragraph": 981,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 74,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "visuddhimagga",
+                        "añña",
+                        "ṭīkā",
+                        "nidānakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 981,
+                    "book_name": ""
+                }
+            ]
+        },
+        "69": {
+            "max_paragraph": 4241,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 75,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "abhidhamma",
+                        "paṭṭhāna",
+                        "paṭṭhānapāḷi",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4241,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "70": {
+            "max_paragraph": 6004,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 76,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "abhidhamma",
+                        "mūla",
+                        "paṭṭhāna",
+                        "paṭṭhānapāḷi",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 6004,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "71": {
+            "max_paragraph": 8046,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 77,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "paṭṭhānapāḷi",
+                        "paṭṭhāna",
+                        "abhidhamma",
+                        "mūla",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 8046,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "72": {
+            "max_paragraph": 5169,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 78,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "paṭṭhānapāḷi",
+                        "abhidhamma",
+                        "mūla",
+                        "paṭṭhāna",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 5169,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "73": {
+            "max_paragraph": 2436,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 79,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "dhammasaṅgaṇī",
+                        "mūla",
+                        "pāḷi",
+                        "abhidhamma"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2436,
+                    "book_name": "abhi1"
+                }
+            ]
+        },
+        "74": {
+            "max_paragraph": 3427,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 80,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "abhidhamma",
+                        "vibhaṅga",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3427,
+                    "book_name": "abhi2"
+                }
+            ]
+        },
+        "75": {
+            "max_paragraph": 673,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 81,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "abhidhamma",
+                        "pāḷi",
+                        "mūla",
+                        "dhātukathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 673,
+                    "book_name": "abhi3"
+                }
+            ]
+        },
+        "76": {
+            "max_paragraph": 561,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 82,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "puggalapaññatti",
+                        "abhidhamma",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 561,
+                    "book_name": "abhi4"
+                }
+            ]
+        },
+        "77": {
+            "max_paragraph": 3460,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 83,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "kathāvatthu",
+                        "mūla",
+                        "abhidhamma"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3460,
+                    "book_name": "abhi5"
+                }
+            ]
+        },
+        "78": {
+            "max_paragraph": 4774,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 84,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "yamakapāḷi",
+                        "pāḷi",
+                        "mūla",
+                        "abhidhamma",
+                        "yamaka"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4774,
+                    "book_name": "abhi6"
+                }
+            ]
+        },
+        "79": {
+            "max_paragraph": 3859,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 85,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "yamaka",
+                        "abhidhamma",
+                        "mūla",
+                        "pāḷi",
+                        "yamakapāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3859,
+                    "book_name": "abhi6"
+                }
+            ]
+        },
+        "80": {
+            "max_paragraph": 5586,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 86,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "yamaka",
+                        "abhidhamma",
+                        "mūla",
+                        "pāḷi",
+                        "yamakapāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 5586,
+                    "book_name": "abhi6"
+                }
+            ]
+        },
+        "81": {
+            "max_paragraph": 4301,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 87,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "paṭṭhāna",
+                        "abhidhamma",
+                        "pāḷi",
+                        "paṭṭhānapāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4301,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "82": {
+            "max_paragraph": 1604,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 88,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "sutta",
+                        "nipāta",
+                        "mūla",
+                        "pāḷi",
+                        "dasakanipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1604,
+                    "book_name": "an10"
+                }
+            ]
+        },
+        "83": {
+            "max_paragraph": 245,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 89,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "sutta",
+                        "ekādasakanipāta",
+                        "pāḷi",
+                        "aṅguttaranikāya",
+                        "nipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 245,
+                    "book_name": "an11"
+                }
+            ]
+        },
+        "84": {
+            "max_paragraph": 400,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 90,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "nipāta",
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "aṅguttaranikāya",
+                        "ekakanipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 400,
+                    "book_name": "an1"
+                }
+            ]
+        },
+        "85": {
+            "max_paragraph": 318,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 91,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "pāḷi",
+                        "dukanipāta",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 318,
+                    "book_name": "an2"
+                }
+            ]
+        },
+        "86": {
+            "max_paragraph": 1336,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 92,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "tikanipāta",
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "mūla",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1336,
+                    "book_name": "an3"
+                }
+            ]
+        },
+        "87": {
+            "max_paragraph": 1950,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 93,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "nipāta",
+                        "catukkanipāta",
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "aṅguttaranikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1950,
+                    "book_name": "an4"
+                }
+            ]
+        },
+        "88": {
+            "max_paragraph": 1632,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 94,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "sutta",
+                        "mūla",
+                        "aṅguttaranikāya",
+                        "nipāta",
+                        "pañcakanipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1632,
+                    "book_name": "an5"
+                }
+            ]
+        },
+        "89": {
+            "max_paragraph": 857,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 95,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "nipāta",
+                        "chakkanipāta",
+                        "mūla",
+                        "sutta",
+                        "pāḷi",
+                        "aṅguttaranikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 857,
+                    "book_name": "an6"
+                }
+            ]
+        },
+        "90": {
+            "max_paragraph": 791,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 96,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "sattakanipāta",
+                        "aṅguttaranikāya",
+                        "nipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 791,
+                    "book_name": "an7"
+                }
+            ]
+        },
+        "91": {
+            "max_paragraph": 1041,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 97,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "aṭṭhakanipāta",
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1041,
+                    "book_name": "an8"
+                }
+            ]
+        },
+        "92": {
+            "max_paragraph": 502,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 98,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "nipāta",
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "aṅguttaranikāya",
+                        "navakanipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 502,
+                    "book_name": "an9"
+                }
+            ]
+        },
+        "93": {
+            "max_paragraph": 1074,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 99,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sīlakkhandhavagga",
+                        "dīghanikāya",
+                        "pāḷi",
+                        "mūla",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1074,
+                    "book_name": "dn1"
+                }
+            ]
+        },
+        "94": {
+            "max_paragraph": 1559,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 100,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mahāvagga",
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "dīghanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1559,
+                    "book_name": "dn2"
+                }
+            ]
+        },
+        "95": {
+            "max_paragraph": 1910,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 101,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "dīghanikāya",
+                        "pāthikavagga",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1910,
+                    "book_name": "dn3"
+                }
+            ]
+        },
+        "96": {
+            "max_paragraph": 2489,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 102,
+                    "from_paragraph": 4,
+                    "type": "atthakatha",
+                    "tags": [
+                        "abhidhamma",
+                        "aṭṭhasālinī",
+                        "aṭṭhakathā",
+                        "dhammasaṅgaṇī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2489,
+                    "book_name": "abhi1"
+                }
+            ]
+        },
+        "97": {
+            "max_paragraph": 2346,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 103,
+                    "from_paragraph": 4,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "sammohavinodanī",
+                        "abhidhamma",
+                        "vibhaṅga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2346,
+                    "book_name": "abhi2"
+                }
+            ]
+        },
+        "98": {
+            "max_paragraph": 2611,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 104,
+                    "from_paragraph": 4,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "abhidhamma",
+                        "pañcapakaraṇa",
+                        "dhātukathā"
+                    ]
+                },
+                {
+                    "book_id": 105,
+                    "from_paragraph": 173,
+                    "type": "atthakatha",
+                    "tags": [
+                        "puggalapaññatti",
+                        "pañcapakaraṇa",
+                        "abhidhamma",
+                        "aṭṭhakathā"
+                    ]
+                },
+                {
+                    "book_id": 106,
+                    "from_paragraph": 474,
+                    "type": "atthakatha",
+                    "tags": [
+                        "kathāvatthu",
+                        "abhidhamma",
+                        "aṭṭhakathā",
+                        "pañcapakaraṇa"
+                    ]
+                },
+                {
+                    "book_id": 107,
+                    "from_paragraph": 1623,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "abhidhamma",
+                        "pañcapakaraṇa",
+                        "yamaka"
+                    ]
+                },
+                {
+                    "book_id": 108,
+                    "from_paragraph": 1880,
+                    "type": "atthakatha",
+                    "tags": [
+                        "paṭṭhāna",
+                        "aṭṭhakathā",
+                        "abhidhamma",
+                        "pañcapakaraṇa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 172,
+                    "book_name": "abhi3"
+                },
+                {
+                    "para_from": 173,
+                    "para_to": 473,
+                    "book_name": "abhi4"
+                },
+                {
+                    "para_from": 474,
+                    "para_to": 1622,
+                    "book_name": "abhi5"
+                },
+                {
+                    "para_from": 1623,
+                    "para_to": 1879,
+                    "book_name": "abhi6"
+                },
+                {
+                    "para_from": 1880,
+                    "para_to": 2611,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "99": {
+            "max_paragraph": 1624,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 109,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "sutta",
+                        "ekakanipāta",
+                        "manorathapūraṇī",
+                        "aṅguttaranikāya",
+                        "nipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 49,
+                    "book_name": "an1_A"
+                },
+                {
+                    "para_from": 50,
+                    "para_to": 1624,
+                    "book_name": "an1"
+                }
+            ]
+        },
+        "100": {
+            "max_paragraph": 1722,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 110,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "aṭṭhakathā",
+                        "manorathapūraṇī",
+                        "sutta",
+                        "dukanipāta"
+                    ]
+                },
+                {
+                    "book_id": 111,
+                    "from_paragraph": 325,
+                    "type": "atthakatha",
+                    "tags": [
+                        "manorathapūraṇī",
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "tikanipāta"
+                    ]
+                },
+                {
+                    "book_id": 112,
+                    "from_paragraph": 997,
+                    "type": "atthakatha",
+                    "tags": [
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "manorathapūraṇī",
+                        "catukkanipāta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 322,
+                    "book_name": "an2"
+                },
+                {
+                    "para_from": 323,
+                    "para_to": 994,
+                    "book_name": "an3"
+                },
+                {
+                    "para_from": 995,
+                    "para_to": 1722,
+                    "book_name": "an4"
+                }
+            ]
+        },
+        "101": {
+            "max_paragraph": 985,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 113,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "manorathapūraṇī",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "aṅguttaranikāya",
+                        "nipāta",
+                        "pañcakanipāta"
+                    ]
+                },
+                {
+                    "book_id": 114,
+                    "from_paragraph": 503,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "manorathapūraṇī",
+                        "chakkanipāta",
+                        "nipāta"
+                    ]
+                },
+                {
+                    "book_id": 115,
+                    "from_paragraph": 792,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sattakanipāta",
+                        "nipāta",
+                        "manorathapūraṇī",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "aṅguttaranikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 500,
+                    "book_name": "an5"
+                },
+                {
+                    "para_from": 501,
+                    "para_to": 789,
+                    "book_name": "an6"
+                },
+                {
+                    "para_from": 790,
+                    "para_to": 985,
+                    "book_name": "an7"
+                }
+            ]
+        },
+        "102": {
+            "max_paragraph": 796,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 116,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "sutta",
+                        "aṭṭhakanipāta",
+                        "manorathapūraṇī",
+                        "nipāta",
+                        "aṅguttaranikāya"
+                    ]
+                },
+                {
+                    "book_id": 117,
+                    "from_paragraph": 275,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "manorathapūraṇī",
+                        "navakanipāta",
+                        "nipāta",
+                        "aṭṭhakathā",
+                        "sutta"
+                    ]
+                },
+                {
+                    "book_id": 118,
+                    "from_paragraph": 409,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "dasakanipāta",
+                        "aṭṭhakathā",
+                        "nipāta",
+                        "manorathapūraṇī",
+                        "sutta"
+                    ]
+                },
+                {
+                    "book_id": 119,
+                    "from_paragraph": 706,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "nipāta",
+                        "ekādasakanipāta",
+                        "manorathapūraṇī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 272,
+                    "book_name": "an8"
+                },
+                {
+                    "para_from": 273,
+                    "para_to": 406,
+                    "book_name": "an9"
+                },
+                {
+                    "para_from": 407,
+                    "para_to": 703,
+                    "book_name": "an10"
+                },
+                {
+                    "para_from": 704,
+                    "para_to": 796,
+                    "book_name": "an11"
+                }
+            ]
+        },
+        "103": {
+            "max_paragraph": 1507,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 120,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "sumaṅgalavilāsinī",
+                        "sīlakkhandhavagga",
+                        "dīghanikāya",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 198,
+                    "book_name": "dn1_A"
+                },
+                {
+                    "para_from": 199,
+                    "para_to": 1507,
+                    "book_name": "dn1"
+                }
+            ]
+        },
+        "104": {
+            "max_paragraph": 1712,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 121,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "dīghanikāya",
+                        "mahāvagga",
+                        "sumaṅgalavilāsinī",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1712,
+                    "book_name": "dn2"
+                }
+            ]
+        },
+        "105": {
+            "max_paragraph": 1131,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 122,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "pāthikavagga",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "dīghanikāya",
+                        "sumaṅgalavilāsinī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1131,
+                    "book_name": "dn3"
+                }
+            ]
+        },
+        "106": {
+            "max_paragraph": 4548,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 123,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "khuddakanikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "therīgāthā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4548,
+                    "book_name": "kn9"
+                }
+            ]
+        },
+        "107": {
+            "max_paragraph": 3875,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 124,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "apadāna",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "therāpadāna",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2141,
+                    "book_name": "kn10_A"
+                },
+                {
+                    "para_from": 2142,
+                    "para_to": 3875,
+                    "book_name": "kn10_B"
+                }
+            ]
+        },
+        "108": {
+            "max_paragraph": 4137,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 125,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "vaṃsa ganthasaṅgaha",
+                        "buddhavaṃsa",
+                        "khuddakanikāya",
+                        "aṭṭhakathā",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4137,
+                    "book_name": "kn12"
+                }
+            ]
+        },
+        "109": {
+            "max_paragraph": 2126,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 126,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "carita",
+                        "cariyāpiṭaka",
+                        "khuddakanikāya",
+                        "aṭṭhakathā",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2126,
+                    "book_name": "kn13"
+                }
+            ]
+        },
+        "110": {
+            "max_paragraph": 3117,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 127,
+                    "from_paragraph": 4,
+                    "type": "atthakatha",
+                    "tags": [
+                        "jātaka",
+                        "aṭṭhakathā",
+                        "khuddakanikāya",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3117,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "111": {
+            "max_paragraph": 2997,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 128,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "khuddakanikāya",
+                        "sutta",
+                        "jātaka",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2997,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "112": {
+            "max_paragraph": 4868,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 129,
+                    "from_paragraph": 4,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "sutta",
+                        "khuddakanikāya",
+                        "jātaka"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4868,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "113": {
+            "max_paragraph": 6738,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 130,
+                    "from_paragraph": 4,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "aṭṭhakathā",
+                        "khuddakanikāya",
+                        "jātaka"
+                    ]
+                },
+                {
+                    "book_id": 131,
+                    "from_paragraph": 5312,
+                    "type": "atthakatha",
+                    "tags": [
+                        "jātaka",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 6738,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "114": {
+            "max_paragraph": 5079,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 132,
+                    "from_paragraph": 1,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "jātaka",
+                        "khuddakanikāya",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 5079,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "115": {
+            "max_paragraph": 3688,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 133,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "khuddakanikāya",
+                        "jātaka",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3688,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "116": {
+            "max_paragraph": 1235,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 134,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "khuddakapāṭha",
+                        "paramatthajotika",
+                        "khuddakanikāya",
+                        "aṭṭhakathā",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1235,
+                    "book_name": "kn1"
+                }
+            ]
+        },
+        "117": {
+            "max_paragraph": 6463,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 135,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "jātaka",
+                        "khuddakanikāya",
+                        "aṭṭhakathā",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 6463,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "118": {
+            "max_paragraph": 1833,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 136,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "niddesa",
+                        "mahāniddesa",
+                        "khuddakanikāya",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1833,
+                    "book_name": "kn15"
+                }
+            ]
+        },
+        "119": {
+            "max_paragraph": 753,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 137,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "sutta",
+                        "cūḷaniddesa",
+                        "niddesa",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 753,
+                    "book_name": "kn16"
+                }
+            ]
+        },
+        "120": {
+            "max_paragraph": 2526,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 138,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "khuddakanikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "paṭisambhidāmagga",
+                        "saddhammappakāsinī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2526,
+                    "book_name": "kn17"
+                }
+            ]
+        },
+        "121": {
+            "max_paragraph": 1096,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 139,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "khuddakanikāya",
+                        "nettippakaraṇa",
+                        "netti",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1096,
+                    "book_name": "kn19"
+                }
+            ]
+        },
+        "122": {
+            "max_paragraph": 5231,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 140,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "dhammapada",
+                        "khuddakanikāya",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 5231,
+                    "book_name": "kn2"
+                }
+            ]
+        },
+        "123": {
+            "max_paragraph": 1688,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 141,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "khuddakanikāya",
+                        "udāna",
+                        "sutta",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1688,
+                    "book_name": "kn3"
+                }
+            ]
+        },
+        "124": {
+            "max_paragraph": 1759,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 142,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "khuddakanikāya",
+                        "itivuttaka",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1759,
+                    "book_name": "kn4"
+                }
+            ]
+        },
+        "125": {
+            "max_paragraph": 2689,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 143,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "suttanipāta",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "khuddakanikāya",
+                        "nipāta",
+                        "paramatthajotika"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2689,
+                    "book_name": "kn5"
+                }
+            ]
+        },
+        "126": {
+            "max_paragraph": 4017,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 144,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "khuddakanikāya",
+                        "vimānavatthu",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4017,
+                    "book_name": "kn6"
+                }
+            ]
+        },
+        "127": {
+            "max_paragraph": 3236,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 145,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "petavatthu",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3236,
+                    "book_name": "kn7"
+                }
+            ]
+        },
+        "128": {
+            "max_paragraph": 5412,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 146,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "khuddakanikāya",
+                        "theragāthā",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 5412,
+                    "book_name": "kn8"
+                }
+            ]
+        },
+        "129": {
+            "max_paragraph": 6607,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 147,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "theragāthā",
+                        "sutta",
+                        "aṭṭhakathā",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 6607,
+                    "book_name": "kn8"
+                }
+            ]
+        },
+        "130": {
+            "max_paragraph": 2912,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 148,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "mūlapaṇṇāsa",
+                        "aṭṭhakathā",
+                        "majjhimanikāya",
+                        "papañcasūdanī",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 46,
+                    "book_name": "mn1_A"
+                },
+                {
+                    "para_from": 47,
+                    "para_to": 2912,
+                    "book_name": "mn1"
+                }
+            ]
+        },
+        "131": {
+            "max_paragraph": 1339,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 149,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sutta",
+                        "aṭṭhakathā",
+                        "papañcasūdanī",
+                        "majjhimapaṇṇāsa",
+                        "majjhimanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1339,
+                    "book_name": "mn2"
+                }
+            ]
+        },
+        "132": {
+            "max_paragraph": 1107,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 150,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "majjhimanikāya",
+                        "aṭṭhakathā",
+                        "papañcasūdanī",
+                        "sutta",
+                        "uparipaṇṇāsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1107,
+                    "book_name": "mn3"
+                }
+            ]
+        },
+        "133": {
+            "max_paragraph": 1478,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 151,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "saṃyuttanikāya",
+                        "sagāthāvagga",
+                        "sāratthappakāsinī",
+                        "aṭṭhakathā",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 43,
+                    "book_name": "sn1_A"
+                },
+                {
+                    "para_from": 44,
+                    "para_to": 1478,
+                    "book_name": "sn1"
+                }
+            ]
+        },
+        "134": {
+            "max_paragraph": 978,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 152,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "sutta",
+                        "saṃyuttanikāya",
+                        "sāratthappakāsinī",
+                        "nidānavagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 978,
+                    "book_name": "sn2"
+                }
+            ]
+        },
+        "135": {
+            "max_paragraph": 491,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 153,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "saṃyuttanikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "sāratthappakāsinī",
+                        "khandhavagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 491,
+                    "book_name": "sn3"
+                }
+            ]
+        },
+        "136": {
+            "max_paragraph": 799,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 154,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "saḷāyatanavagga",
+                        "sāratthappakāsinī",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "saṃyuttanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 799,
+                    "book_name": "sn4"
+                }
+            ]
+        },
+        "137": {
+            "max_paragraph": 1016,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 155,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "sāratthappakāsinī",
+                        "saṃyuttanikāya",
+                        "aṭṭhakathā",
+                        "sutta",
+                        "mahāvagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1016,
+                    "book_name": "sn5"
+                }
+            ]
+        },
+        "138": {
+            "max_paragraph": 2974,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 156,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "pārājika",
+                        "vinaya",
+                        "aṭṭhakathā",
+                        "samantapāsādikā",
+                        "suttavibhaṅga",
+                        "mahāvibhaṅga",
+                        "pārājikakaṇḍa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2974,
+                    "book_name": "vin1"
+                }
+            ]
+        },
+        "139": {
+            "max_paragraph": 1466,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 157,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "mahāvibhaṅga",
+                        "suttavibhaṅga",
+                        "samantapāsādikā",
+                        "aṭṭhakathā",
+                        "vinaya",
+                        "pācittiya-aṭṭhakathā",
+                        "pācittiya"
+                    ]
+                },
+                {
+                    "book_id": 280,
+                    "from_paragraph": 925,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "samantapāsādikā",
+                        "vinaya",
+                        "bhikkhunīvibhaṅga",
+                        "pācittiya-aṭṭhakathā",
+                        "pācittiya",
+                        "suttavibhaṅga",
+                        "bhikkhunī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1466,
+                    "book_name": "vin2"
+                }
+            ]
+        },
+        "140": {
+            "max_paragraph": 923,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 158,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "aṭṭhakathā",
+                        "khandhaka",
+                        "samantapāsādikā",
+                        "mahāvagga",
+                        "vinaya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 923,
+                    "book_name": "vin3"
+                }
+            ]
+        },
+        "141": {
+            "max_paragraph": 669,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 159,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "samantapāsādikā",
+                        "cūḷavagga",
+                        "khandhaka",
+                        "vinaya",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 669,
+                    "book_name": "vin4"
+                }
+            ]
+        },
+        "142": {
+            "max_paragraph": 661,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 160,
+                    "from_paragraph": 3,
+                    "type": "atthakatha",
+                    "tags": [
+                        "samantapāsādikā",
+                        "parivāra",
+                        "parivārapāḷi",
+                        "vinaya",
+                        "aṭṭhakathā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 661,
+                    "book_name": "vin5"
+                }
+            ]
+        },
+        "143": {
+            "max_paragraph": 14646,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 161,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "apadāna",
+                        "therāpadāna",
+                        "khuddakanikāya",
+                        "sutta",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 14646,
+                    "book_name": "kn10"
+                }
+            ]
+        },
+        "144": {
+            "max_paragraph": 10673,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 162,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "khuddakanikāya",
+                        "therāpadāna",
+                        "apadāna",
+                        "pāḷi",
+                        "mūla",
+                        "sutta"
+                    ]
+                },
+                {
+                    "book_id": 163,
+                    "from_paragraph": 6534,
+                    "type": "mula",
+                    "tags": [
+                        "khuddakanikāya",
+                        "pāḷi",
+                        "apadāna",
+                        "therīapadāna",
+                        "sutta",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 6531,
+                    "book_name": "kn10"
+                },
+                {
+                    "para_from": 6532,
+                    "para_to": 10673,
+                    "book_name": "kn11"
+                }
+            ]
+        },
+        "145": {
+            "max_paragraph": 3282,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 164,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "sutta",
+                        "khuddakanikāya",
+                        "pāḷi",
+                        "buddhavaṃsa",
+                        "vaṃsa ganthasaṅgaha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 3282,
+                    "book_name": "kn12"
+                }
+            ]
+        },
+        "146": {
+            "max_paragraph": 1199,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 165,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "carita",
+                        "pāḷi",
+                        "cariyāpiṭaka",
+                        "mūla",
+                        "sutta",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1199,
+                    "book_name": "kn13"
+                }
+            ]
+        },
+        "147": {
+            "max_paragraph": 11528,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 166,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "sutta",
+                        "khuddakanikāya",
+                        "pāḷi",
+                        "jātaka"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 11528,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "148": {
+            "max_paragraph": 10506,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 167,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "khuddakanikāya",
+                        "mūla",
+                        "pāḷi",
+                        "jātaka",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 10506,
+                    "book_name": "kn14"
+                }
+            ]
+        },
+        "149": {
+            "max_paragraph": 2927,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 168,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "niddesa",
+                        "khuddakanikāya",
+                        "sutta",
+                        "mahāniddesa",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2927,
+                    "book_name": "kn15"
+                }
+            ]
+        },
+        "150": {
+            "max_paragraph": 2771,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 169,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "khuddakanikāya",
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "niddesa",
+                        "cūḷaniddesa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2771,
+                    "book_name": "kn16"
+                }
+            ]
+        },
+        "151": {
+            "max_paragraph": 2044,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 170,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "khuddakanikāya",
+                        "pāḷi",
+                        "mūla",
+                        "paṭisambhidāmagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2044,
+                    "book_name": "kn17"
+                }
+            ]
+        },
+        "152": {
+            "max_paragraph": 2493,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 171,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "milindapañha",
+                        "khuddakanikāya",
+                        "sutta",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2493,
+                    "book_name": "kn18"
+                }
+            ]
+        },
+        "153": {
+            "max_paragraph": 1624,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 172,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "sutta",
+                        "khuddakanikāya",
+                        "pāḷi",
+                        "nettippakaraṇa",
+                        "netti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1624,
+                    "book_name": "kn19"
+                }
+            ]
+        },
+        "154": {
+            "max_paragraph": 276,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 173,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "khuddakapāṭha",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 276,
+                    "book_name": "kn1"
+                }
+            ]
+        },
+        "155": {
+            "max_paragraph": 1217,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 174,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "peṭakopadesa",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1217,
+                    "book_name": "kn20"
+                }
+            ]
+        },
+        "156": {
+            "max_paragraph": 1394,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 175,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "dhammapada",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1394,
+                    "book_name": "kn2"
+                }
+            ]
+        },
+        "157": {
+            "max_paragraph": 965,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 176,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "khuddakanikāya",
+                        "sutta",
+                        "udāna",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 965,
+                    "book_name": "kn3"
+                }
+            ]
+        },
+        "158": {
+            "max_paragraph": 1194,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 177,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "itivuttaka",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1194,
+                    "book_name": "kn4"
+                }
+            ]
+        },
+        "159": {
+            "max_paragraph": 4051,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 178,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "suttanipāta",
+                        "nipāta",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 4051,
+                    "book_name": "kn5"
+                }
+            ]
+        },
+        "160": {
+            "max_paragraph": 3279,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 179,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "vimānavatthu",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 3279,
+                    "book_name": "kn6"
+                }
+            ]
+        },
+        "161": {
+            "max_paragraph": 2655,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 180,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "petavatthu",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2655,
+                    "book_name": "kn7"
+                }
+            ]
+        },
+        "162": {
+            "max_paragraph": 4669,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 181,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "sutta",
+                        "khuddakanikāya",
+                        "mūla",
+                        "theragāthā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 4669,
+                    "book_name": "kn8"
+                }
+            ]
+        },
+        "163": {
+            "max_paragraph": 1785,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 182,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "therīgāthā",
+                        "pāḷi",
+                        "mūla",
+                        "khuddakanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1785,
+                    "book_name": "kn9"
+                }
+            ]
+        },
+        "164": {
+            "max_paragraph": 1797,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 183,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūlapaṇṇāsa",
+                        "majjhimanikāya",
+                        "sutta",
+                        "mūla",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1797,
+                    "book_name": "mn1"
+                }
+            ]
+        },
+        "165": {
+            "max_paragraph": 1690,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 184,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "majjhimapaṇṇāsa",
+                        "mūla",
+                        "sutta",
+                        "majjhimanikāya",
+                        "pāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1690,
+                    "book_name": "mn2"
+                }
+            ]
+        },
+        "166": {
+            "max_paragraph": 1463,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 185,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "majjhimanikāya",
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "uparipaṇṇāsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1463,
+                    "book_name": "mn3"
+                }
+            ]
+        },
+        "167": {
+            "max_paragraph": 3498,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 186,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "sagāthāvagga",
+                        "saṃyuttanikāya",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 3498,
+                    "book_name": "sn1"
+                }
+            ]
+        },
+        "168": {
+            "max_paragraph": 1427,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 187,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "mūla",
+                        "nidānavagga",
+                        "saṃyuttanikāya",
+                        "pāḷi",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1427,
+                    "book_name": "sn2"
+                }
+            ]
+        },
+        "169": {
+            "max_paragraph": 1467,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 188,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "saṃyuttanikāya",
+                        "sutta",
+                        "khandhavagga",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1467,
+                    "book_name": "sn3"
+                }
+            ]
+        },
+        "170": {
+            "max_paragraph": 2020,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 189,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "mūla",
+                        "pāḷi",
+                        "saṃyuttanikāya",
+                        "saḷāyatanavagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2020,
+                    "book_name": "sn4"
+                }
+            ]
+        },
+        "171": {
+            "max_paragraph": 2852,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 190,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "sutta",
+                        "saṃyuttanikāya",
+                        "mahāvagga",
+                        "pāḷi",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2852,
+                    "book_name": "sn5"
+                }
+            ]
+        },
+        "172": {
+            "max_paragraph": 722,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 191,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhamma",
+                        "mūlaṭīkā",
+                        "ṭīkā",
+                        "dhammasaṅgaṇī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 722,
+                    "book_name": "abhi1"
+                }
+            ]
+        },
+        "173": {
+            "max_paragraph": 2219,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 192,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "vibhaṅga",
+                        "mūlaṭīkā",
+                        "abhidhamma",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 193,
+                    "from_paragraph": 1155,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "mūlaṭīkā",
+                        "abhidhamma",
+                        "vibhaṅga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2219,
+                    "book_name": "abhi2"
+                }
+            ]
+        },
+        "174": {
+            "max_paragraph": 1487,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 194,
+                    "from_paragraph": 4,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "abhidhamma",
+                        "dhātukathā",
+                        "pañcapakaraṇa",
+                        "mūlaṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 195,
+                    "from_paragraph": 100,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhamma",
+                        "pañcapakaraṇa",
+                        "puggalapaññatti",
+                        "mūlaṭīkā",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 196,
+                    "from_paragraph": 201,
+                    "type": "tika",
+                    "tags": [
+                        "pañcapakaraṇa",
+                        "abhidhamma",
+                        "ṭīkā",
+                        "mūlaṭīkā",
+                        "kathāvatthu"
+                    ]
+                },
+                {
+                    "book_id": 197,
+                    "from_paragraph": 865,
+                    "type": "tika",
+                    "tags": [
+                        "yamaka",
+                        "abhidhamma",
+                        "pañcapakaraṇa",
+                        "ṭīkā",
+                        "mūlaṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 198,
+                    "from_paragraph": 1059,
+                    "type": "tika",
+                    "tags": [
+                        "paṭṭhāna",
+                        "pañcapakaraṇa",
+                        "mūlaṭīkā",
+                        "ṭīkā",
+                        "abhidhamma"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 99,
+                    "book_name": "abhi3"
+                },
+                {
+                    "para_from": 100,
+                    "para_to": 200,
+                    "book_name": "abhi4"
+                },
+                {
+                    "para_from": 201,
+                    "para_to": 864,
+                    "book_name": "abhi5"
+                },
+                {
+                    "para_from": 865,
+                    "para_to": 1058,
+                    "book_name": "abhi6"
+                },
+                {
+                    "para_from": 1059,
+                    "para_to": 1487,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "175": {
+            "max_paragraph": 725,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 199,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "dhammasaṅgaṇī",
+                        "abhidhamma",
+                        "ṭīkā",
+                        "anuṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 725,
+                    "book_name": "abhi1"
+                }
+            ]
+        },
+        "176": {
+            "max_paragraph": 1511,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 200,
+                    "from_paragraph": 4,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhamma",
+                        "ṭīkā",
+                        "anuṭīkā",
+                        "dhātukathā",
+                        "pañcapakaraṇa"
+                    ]
+                },
+                {
+                    "book_id": 201,
+                    "from_paragraph": 117,
+                    "type": "tika",
+                    "tags": [
+                        "anuṭīkā",
+                        "ṭīkā",
+                        "abhidhamma",
+                        "puggalapaññatti",
+                        "pañcapakaraṇa"
+                    ]
+                },
+                {
+                    "book_id": 202,
+                    "from_paragraph": 213,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhamma",
+                        "ṭīkā",
+                        "anuṭīkā",
+                        "pañcapakaraṇa",
+                        "kathāvatthu"
+                    ]
+                },
+                {
+                    "book_id": 203,
+                    "from_paragraph": 917,
+                    "type": "tika",
+                    "tags": [
+                        "pañcapakaraṇa",
+                        "anuṭīkā",
+                        "yamaka",
+                        "abhidhamma",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 204,
+                    "from_paragraph": 1139,
+                    "type": "tika",
+                    "tags": [
+                        "anuṭīkā",
+                        "ṭīkā",
+                        "abhidhamma",
+                        "paṭṭhāna",
+                        "pañcapakaraṇa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 116,
+                    "book_name": "abhi3"
+                },
+                {
+                    "para_from": 117,
+                    "para_to": 212,
+                    "book_name": "abhi4"
+                },
+                {
+                    "para_from": 213,
+                    "para_to": 916,
+                    "book_name": "abhi5"
+                },
+                {
+                    "para_from": 917,
+                    "para_to": 1138,
+                    "book_name": "abhi6"
+                },
+                {
+                    "para_from": 1139,
+                    "para_to": 1511,
+                    "book_name": "abhi7"
+                }
+            ]
+        },
+        "177": {
+            "max_paragraph": 15499,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 205,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhamma",
+                        "ṭīkā",
+                        "abhidhammāvatāro",
+                        "abhidhammāvatāra"
+                    ]
+                },
+                {
+                    "book_id": 206,
+                    "from_paragraph": 4805,
+                    "type": "tika",
+                    "tags": [
+                        "nāmarūpapariccheda",
+                        "abhidhamma",
+                        "ṭīkā",
+                        "abhidhammāvatāro"
+                    ]
+                },
+                {
+                    "book_id": 207,
+                    "from_paragraph": 10627,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhammāvatāro",
+                        "abhidhamma",
+                        "ṭīkā",
+                        "paramatthavinicchaya"
+                    ]
+                },
+                {
+                    "book_id": 208,
+                    "from_paragraph": 14272,
+                    "type": "tika",
+                    "tags": [
+                        "saccasaṅkhepa",
+                        "ṭīkā",
+                        "abhidhamma",
+                        "abhidhammāvatāro"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 4804,
+                    "book_name": "abhi8"
+                },
+                {
+                    "para_from": 4805,
+                    "para_to": 15499,
+                    "book_name": ""
+                }
+            ]
+        },
+        "178": {
+            "max_paragraph": 1838,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 209,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhammatthasaṅgaha",
+                        "abhidhamma",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 210,
+                    "from_paragraph": 875,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhammatthasaṅgaha",
+                        "ṭīkā",
+                        "abhidhamma"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1838,
+                    "book_name": "abhi9"
+                }
+            ]
+        },
+        "179": {
+            "max_paragraph": 2598,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 211,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhammāvatāra",
+                        "avatāra",
+                        "ṭīkā",
+                        "purāṇaṭīkā",
+                        "abhidhamma"
+                    ]
+                },
+                {
+                    "book_id": 212,
+                    "from_paragraph": 872,
+                    "type": "tika",
+                    "tags": [
+                        "abhidhammāvatāra",
+                        "ṭīkā",
+                        "avatāra",
+                        "abhidhamma",
+                        "abhinavaṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2572,
+                    "book_name": "abhi8"
+                },
+                {
+                    "para_from": 2573,
+                    "para_to": 2598,
+                    "book_name": "abhi8_A"
+                }
+            ]
+        },
+        "180": {
+            "max_paragraph": 2826,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 213,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "mātikā",
+                        "abhidhammamātikā",
+                        "pāḷi",
+                        "abhidhamma",
+                        "ṭīkā",
+                        "abhidhammamātikāpāḷi"
+                    ]
+                },
+                {
+                    "book_id": 214,
+                    "from_paragraph": 1221,
+                    "type": "tika",
+                    "tags": [
+                        "pāḷi",
+                        "abhidhamma",
+                        "ṭīkā",
+                        "abhidhammamātikā",
+                        "mohavicchedanī",
+                        "mātikā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2826,
+                    "book_name": ""
+                }
+            ]
+        },
+        "181": {
+            "max_paragraph": 1173,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 215,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "aṅguttaranikāya",
+                        "ekakanipāta",
+                        "sāratthamañjūsā",
+                        "nipāta",
+                        "ṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 138,
+                    "book_name": "an1_A"
+                },
+                {
+                    "para_from": 139,
+                    "para_to": 1173,
+                    "book_name": "an1"
+                }
+            ]
+        },
+        "182": {
+            "max_paragraph": 1925,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 216,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "ṭīkā",
+                        "dukanipāta",
+                        "sāratthamañjūsā",
+                        "nipāta",
+                        "sutta"
+                    ]
+                },
+                {
+                    "book_id": 217,
+                    "from_paragraph": 324,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "sāratthamañjūsā",
+                        "tikanipāta",
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 218,
+                    "from_paragraph": 1023,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "aṅguttaranikāya",
+                        "ṭīkā",
+                        "nipāta",
+                        "catukkanipāta",
+                        "sāratthamañjūsā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 321,
+                    "book_name": "an2"
+                },
+                {
+                    "para_from": 322,
+                    "para_to": 1020,
+                    "book_name": "an3"
+                },
+                {
+                    "para_from": 1021,
+                    "para_to": 1925,
+                    "book_name": "an4"
+                }
+            ]
+        },
+        "183": {
+            "max_paragraph": 1026,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 219,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "nipāta",
+                        "sāratthamañjūsā",
+                        "pañcakanipāta",
+                        "aṅguttaranikāya",
+                        "sutta"
+                    ]
+                },
+                {
+                    "book_id": 220,
+                    "from_paragraph": 470,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "ṭīkā",
+                        "aṅguttaranikāya",
+                        "nipāta",
+                        "chakkanipāta",
+                        "sāratthamañjūsā"
+                    ]
+                },
+                {
+                    "book_id": 221,
+                    "from_paragraph": 793,
+                    "type": "tika",
+                    "tags": [
+                        "nipāta",
+                        "sutta",
+                        "aṅguttaranikāya",
+                        "ṭīkā",
+                        "sattakanipāta",
+                        "sāratthamañjūsā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 467,
+                    "book_name": "an5"
+                },
+                {
+                    "para_from": 468,
+                    "para_to": 790,
+                    "book_name": "an6"
+                },
+                {
+                    "para_from": 791,
+                    "para_to": 1026,
+                    "book_name": "an7"
+                }
+            ]
+        },
+        "184": {
+            "max_paragraph": 868,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 222,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "aṭṭhakanipāta",
+                        "ṭīkā",
+                        "sāratthamañjūsā",
+                        "nipāta",
+                        "sutta"
+                    ]
+                },
+                {
+                    "book_id": 223,
+                    "from_paragraph": 278,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "sāratthamañjūsā",
+                        "navakanipāta",
+                        "nipāta",
+                        "aṅguttaranikāya",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 224,
+                    "from_paragraph": 466,
+                    "type": "tika",
+                    "tags": [
+                        "nipāta",
+                        "ṭīkā",
+                        "sutta",
+                        "aṅguttaranikāya",
+                        "dasakanipāta",
+                        "sāratthamañjūsā"
+                    ]
+                },
+                {
+                    "book_id": 225,
+                    "from_paragraph": 776,
+                    "type": "tika",
+                    "tags": [
+                        "aṅguttaranikāya",
+                        "ṭīkā",
+                        "sutta",
+                        "nipāta",
+                        "ekādasakanipāta",
+                        "sāratthamañjūsā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 275,
+                    "book_name": "an8"
+                },
+                {
+                    "para_from": 276,
+                    "para_to": 463,
+                    "book_name": "an9"
+                },
+                {
+                    "para_from": 464,
+                    "para_to": 773,
+                    "book_name": "an10"
+                },
+                {
+                    "para_from": 774,
+                    "para_to": 868,
+                    "book_name": "an11"
+                }
+            ]
+        },
+        "185": {
+            "max_paragraph": 1391,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 226,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "dīghanikāya",
+                        "ṭīkā",
+                        "sīlakkhandhavaggaṭīkā",
+                        "līnatthappakāsanā",
+                        "sīlakkhandhavagga",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 120,
+                    "book_name": "dn1_A"
+                },
+                {
+                    "para_from": 121,
+                    "para_to": 1391,
+                    "book_name": "dn1"
+                }
+            ]
+        },
+        "186": {
+            "max_paragraph": 1495,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 227,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "mahāvagga",
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "dīghanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1495,
+                    "book_name": "dn2"
+                }
+            ]
+        },
+        "187": {
+            "max_paragraph": 1132,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 228,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "pāthikavagga",
+                        "sutta",
+                        "dīghanikāya",
+                        "ṭīkā",
+                        "līnatthappakāsanā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1132,
+                    "book_name": "dn3"
+                }
+            ]
+        },
+        "188": {
+            "max_paragraph": 1574,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 229,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "abhinavaṭīkā",
+                        "sādhuvilāsinī",
+                        "sutta",
+                        "ṭīkā",
+                        "dīghanikāya",
+                        "sīlakkhandhavagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 458,
+                    "book_name": "dn1_A"
+                },
+                {
+                    "para_from": 459,
+                    "para_to": 1574,
+                    "book_name": "dn1"
+                }
+            ]
+        },
+        "189": {
+            "max_paragraph": 1366,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 230,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "sādhuvilāsinī",
+                        "abhinavaṭīkā",
+                        "dīghanikāya",
+                        "sutta",
+                        "ṭīkā",
+                        "sīlakkhandhavagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1366,
+                    "book_name": "dn1"
+                }
+            ]
+        },
+        "190": {
+            "max_paragraph": 764,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 231,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "netti",
+                        "khuddakanikāya",
+                        "ṭīkā",
+                        "sutta",
+                        "nettippakaraṇa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 764,
+                    "book_name": "kn19"
+                }
+            ]
+        },
+        "191": {
+            "max_paragraph": 1670,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 232,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "nettivibhāvinī",
+                        "ṭīkā",
+                        "sutta",
+                        "khuddakanikāya",
+                        "netti"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1670,
+                    "book_name": "kn19"
+                }
+            ]
+        },
+        "192": {
+            "max_paragraph": 2388,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 233,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "mūlapaṇṇāsa",
+                        "majjhimanikāya",
+                        "sutta",
+                        "ṭīkā",
+                        "līnatthappakāsanā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 89,
+                    "book_name": "mn1_A"
+                },
+                {
+                    "para_from": 90,
+                    "para_to": 2388,
+                    "book_name": "mn1"
+                }
+            ]
+        },
+        "193": {
+            "max_paragraph": 906,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 234,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "sutta",
+                        "majjhimanikāya",
+                        "majjhimapaṇṇāsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 906,
+                    "book_name": "mn2"
+                }
+            ]
+        },
+        "194": {
+            "max_paragraph": 858,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 235,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "sutta",
+                        "majjhimanikāya",
+                        "uparipaṇṇāsa"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 858,
+                    "book_name": "mn3"
+                }
+            ]
+        },
+        "195": {
+            "max_paragraph": 1705,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 236,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "līnatthappakāsanā",
+                        "sagāthāvagga",
+                        "saṃyuttanikāya",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1705,
+                    "book_name": "sn1"
+                }
+            ]
+        },
+        "196": {
+            "max_paragraph": 1027,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 237,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "saṃyuttanikāya",
+                        "nidānavagga",
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "sutta"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 1027,
+                    "book_name": "sn2"
+                }
+            ]
+        },
+        "197": {
+            "max_paragraph": 520,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 238,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "khandhavagga",
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "saṃyuttanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 520,
+                    "book_name": "sn3"
+                }
+            ]
+        },
+        "198": {
+            "max_paragraph": 729,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 239,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "saḷāyatanavagga",
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "saṃyuttanikāya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 729,
+                    "book_name": "sn4"
+                }
+            ]
+        },
+        "199": {
+            "max_paragraph": 850,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 240,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "sutta",
+                        "saṃyuttanikāya",
+                        "līnatthappakāsanā",
+                        "ṭīkā",
+                        "mahāvagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 850,
+                    "book_name": "sn5"
+                }
+            ]
+        },
+        "200": {
+            "max_paragraph": 13281,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 241,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "vinicchaya",
+                        "vinayavinicchaya",
+                        "vinaya",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 242,
+                    "from_paragraph": 10176,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "uttaravinicchaya",
+                        "vinicchaya",
+                        "vinaya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 10175,
+                    "book_name": "vin8"
+                },
+                {
+                    "para_from": 10176,
+                    "para_to": 13281,
+                    "book_name": "vin9"
+                }
+            ]
+        },
+        "201": {
+            "max_paragraph": 5124,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 243,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "vinayavinicchayaṭīkā",
+                        "ṭīkā",
+                        "vinaya",
+                        "vinayavinicchaya",
+                        "vinicchaya"
+                    ]
+                },
+                {
+                    "book_id": 244,
+                    "from_paragraph": 4270,
+                    "type": "tika",
+                    "tags": [
+                        "uttaravinicchayaṭīkā",
+                        "ṭīkā",
+                        "vinaya",
+                        "uttaravinicchaya",
+                        "vinicchaya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1,
+                    "book_name": "vin9"
+                },
+                {
+                    "para_from": 2,
+                    "para_to": 4269,
+                    "book_name": "vin8"
+                },
+                {
+                    "para_from": 4270,
+                    "para_to": 5124,
+                    "book_name": "vin9"
+                }
+            ]
+        },
+        "202": {
+            "max_paragraph": 2992,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 245,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "pācityādiyojanā",
+                        "yojanā",
+                        "pācittiyapāḷi",
+                        "ṭīkā",
+                        "vinaya",
+                        "suttavibhaṅga",
+                        "uttaravinicchayaṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1005,
+                    "book_name": "vin2"
+                },
+                {
+                    "para_from": 1006,
+                    "para_to": 1850,
+                    "book_name": "vin3"
+                },
+                {
+                    "para_from": 1851,
+                    "para_to": 2423,
+                    "book_name": "vin4"
+                },
+                {
+                    "para_from": 2424,
+                    "para_to": 2992,
+                    "book_name": "vin5"
+                }
+            ]
+        },
+        "203": {
+            "max_paragraph": 3631,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 246,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "vinaya",
+                        "khuddasikkhā",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 247,
+                    "from_paragraph": 1620,
+                    "type": "tika",
+                    "tags": [
+                        "vinaya",
+                        "khuddasikkhā",
+                        "purāṇaṭīkā",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 248,
+                    "from_paragraph": 2361,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "vinaya",
+                        "abhinavaṭīkā",
+                        "khuddasikkhā"
+                    ]
+                },
+                {
+                    "book_id": 249,
+                    "from_paragraph": 3100,
+                    "type": "tika",
+                    "tags": [
+                        "vinaya",
+                        "ṭīkā",
+                        "mūlasikkhā"
+                    ]
+                },
+                {
+                    "book_id": 250,
+                    "from_paragraph": 3481,
+                    "type": "tika",
+                    "tags": [
+                        "mūlasikkhā",
+                        "ṭīkā",
+                        "vinaya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 3104,
+                    "book_name": "vin10"
+                },
+                {
+                    "para_from": 3105,
+                    "para_to": 3631,
+                    "book_name": "vin11"
+                }
+            ]
+        },
+        "204": {
+            "max_paragraph": 1659,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 251,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "paṭhamo bhāgo",
+                        "ṭīkā",
+                        "dīpanī",
+                        "vinaya",
+                        "suttavibhaṅga",
+                        "mahāvibhaṅga",
+                        "sāratthadīpanī",
+                        "pārājikapāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1659,
+                    "book_name": "vin1"
+                }
+            ]
+        },
+        "205": {
+            "max_paragraph": 1660,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 252,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "mahāvibhaṅga",
+                        "pārājikapāḷi",
+                        "sāratthadīpanī",
+                        "ṭīkā",
+                        "dīpanī",
+                        "vinaya",
+                        "dutiyo bhāgo",
+                        "suttavibhaṅga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1660,
+                    "book_name": "vin1"
+                }
+            ]
+        },
+        "206": {
+            "max_paragraph": 2401,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 253,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "dīpanī",
+                        "ṭīkā",
+                        "vinaya",
+                        "suttavibhaṅga",
+                        "mahāvibhaṅga",
+                        "pācittiyapāḷi",
+                        "sāratthadīpanī",
+                        "tatiyo bhāgo"
+                    ]
+                },
+                {
+                    "book_id": 254,
+                    "from_paragraph": 717,
+                    "type": "tika",
+                    "tags": [
+                        "sāratthadīpanī",
+                        "vinaya",
+                        "khandhaka",
+                        "mahāvagga",
+                        "ṭīkā",
+                        "dīpanī"
+                    ]
+                },
+                {
+                    "book_id": 255,
+                    "from_paragraph": 1753,
+                    "type": "tika",
+                    "tags": [
+                        "cūḷavagga",
+                        "ṭīkā",
+                        "dīpanī",
+                        "vinaya",
+                        "khandhaka",
+                        "sāratthadīpanī"
+                    ]
+                },
+                {
+                    "book_id": 256,
+                    "from_paragraph": 2154,
+                    "type": "tika",
+                    "tags": [
+                        "sāratthadīpanī",
+                        "ṭīkā",
+                        "dīpanī",
+                        "vinaya",
+                        "parivāra",
+                        "parivārapāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 716,
+                    "book_name": "vin2"
+                },
+                {
+                    "para_from": 717,
+                    "para_to": 1752,
+                    "book_name": "vin3"
+                },
+                {
+                    "para_from": 1753,
+                    "para_to": 2153,
+                    "book_name": "vin4"
+                },
+                {
+                    "para_from": 2154,
+                    "para_to": 2401,
+                    "book_name": "vin5"
+                }
+            ]
+        },
+        "207": {
+            "max_paragraph": 2713,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 257,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "dvemātikāpāḷi",
+                        "bhikkhupātimokkha",
+                        "pāḷi",
+                        "vinaya",
+                        "ṭīkā",
+                        "pātimokkha"
+                    ]
+                },
+                {
+                    "book_id": 258,
+                    "from_paragraph": 524,
+                    "type": "tika",
+                    "tags": [
+                        "dvemātikāpāḷi",
+                        "ṭīkā",
+                        "vinaya",
+                        "pāḷi",
+                        "bhikkhunī",
+                        "bhikkhupātimokkha",
+                        "pātimokkha"
+                    ]
+                },
+                {
+                    "book_id": 259,
+                    "from_paragraph": 1215,
+                    "type": "tika",
+                    "tags": [
+                        "dvemātikāpāḷi",
+                        "pātimokkha",
+                        "vinaya",
+                        "ṭīkā",
+                        "kaṅkhāvitaraṇī"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2713,
+                    "book_name": "vin6"
+                }
+            ]
+        },
+        "208": {
+            "max_paragraph": 1673,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 260,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "vinayasaṅgaha",
+                        "ṭīkā",
+                        "vinaya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1673,
+                    "book_name": "vin7"
+                }
+            ]
+        },
+        "209": {
+            "max_paragraph": 2673,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 261,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "vajirabuddhi",
+                        "vinaya",
+                        "ṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 991,
+                    "book_name": "vin1"
+                },
+                {
+                    "para_from": 992,
+                    "para_to": 1714,
+                    "book_name": "vin2"
+                },
+                {
+                    "para_from": 1715,
+                    "para_to": 2216,
+                    "book_name": "vin3"
+                },
+                {
+                    "para_from": 2217,
+                    "para_to": 2427,
+                    "book_name": "vin4"
+                },
+                {
+                    "para_from": 2428,
+                    "para_to": 2673,
+                    "book_name": "vin5"
+                }
+            ]
+        },
+        "210": {
+            "max_paragraph": 3137,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 267,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "vinaya",
+                        "suttavibhaṅga",
+                        "mahāvibhaṅga",
+                        "pārājikapāḷi",
+                        "vimativinodanī"
+                    ]
+                },
+                {
+                    "book_id": 268,
+                    "from_paragraph": 1658,
+                    "type": "tika",
+                    "tags": [
+                        "ṭīkā",
+                        "vimativinodanī",
+                        "pācittiyapāḷi",
+                        "bhikkhunī",
+                        "bhikkhunīvibhaṅga",
+                        "suttavibhaṅga",
+                        "vinaya"
+                    ]
+                },
+                {
+                    "book_id": 269,
+                    "from_paragraph": 1779,
+                    "type": "tika",
+                    "tags": [
+                        "vinaya",
+                        "mahāvagga",
+                        "khandhaka",
+                        "vimativinodanī",
+                        "ṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 270,
+                    "from_paragraph": 2431,
+                    "type": "tika",
+                    "tags": [
+                        "khandhaka",
+                        "cūḷavagga",
+                        "vimativinodanī",
+                        "ṭīkā",
+                        "vinaya"
+                    ]
+                },
+                {
+                    "book_id": 271,
+                    "from_paragraph": 2792,
+                    "type": "tika",
+                    "tags": [
+                        "vinaya",
+                        "parivārapāḷi",
+                        "parivāra",
+                        "vimativinodanī",
+                        "ṭīkā"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1182,
+                    "book_name": "vin1"
+                },
+                {
+                    "para_from": 1183,
+                    "para_to": 1778,
+                    "book_name": "vin2"
+                },
+                {
+                    "para_from": 1779,
+                    "para_to": 2430,
+                    "book_name": "vin3"
+                },
+                {
+                    "para_from": 2431,
+                    "para_to": 2791,
+                    "book_name": "vin4"
+                },
+                {
+                    "para_from": 2792,
+                    "para_to": 3137,
+                    "book_name": "vin5"
+                }
+            ]
+        },
+        "211": {
+            "max_paragraph": 2414,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 272,
+                    "from_paragraph": 3,
+                    "type": "tika",
+                    "tags": [
+                        "vinayālaṅkāra",
+                        "ṭīkā",
+                        "vinaya"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 1934,
+                    "book_name": "vin7"
+                },
+                {
+                    "para_from": 1935,
+                    "para_to": 2414,
+                    "book_name": "vin7_A"
+                }
+            ]
+        },
+        "212": {
+            "max_paragraph": 2517,
+            "name_source": "old_table",
+            "file_types": [
+                {
+                    "book_id": 273,
+                    "from_paragraph": 2,
+                    "type": "tika",
+                    "tags": [
+                        "vinaya",
+                        "pātimokkha",
+                        "kaṅkhāvitaraṇī",
+                        "ṭīkā",
+                        "purāṇaṭīkā"
+                    ]
+                },
+                {
+                    "book_id": 274,
+                    "from_paragraph": 671,
+                    "type": "tika",
+                    "tags": [
+                        "abhinavaṭīkā",
+                        "vinaya",
+                        "ṭīkā",
+                        "kaṅkhāvitaraṇī",
+                        "pātimokkha"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 2517,
+                    "book_name": "vin6"
+                }
+            ]
+        },
+        "213": {
+            "max_paragraph": 2477,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 275,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pārājika",
+                        "vinaya",
+                        "mūla",
+                        "pāḷi",
+                        "suttavibhaṅga",
+                        "mahāvibhaṅga",
+                        "pārājikapāḷi"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2477,
+                    "book_name": "vin1"
+                }
+            ]
+        },
+        "214": {
+            "max_paragraph": 3690,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 276,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pācittiyapāḷi",
+                        "mūla",
+                        "vinaya",
+                        "pāḷi",
+                        "mahāvibhaṅga",
+                        "suttavibhaṅga"
+                    ]
+                },
+                {
+                    "book_id": 281,
+                    "from_paragraph": 2162,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "suttavibhaṅga",
+                        "pācittiyapāḷi",
+                        "bhikkhunī",
+                        "bhikkhunīvibhaṅga",
+                        "vinaya",
+                        "mūla"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 3690,
+                    "book_name": "vin2"
+                }
+            ]
+        },
+        "215": {
+            "max_paragraph": 2759,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 277,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "mūla",
+                        "vinaya",
+                        "khandhaka",
+                        "mahāvagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2759,
+                    "book_name": "vin3"
+                }
+            ]
+        },
+        "216": {
+            "max_paragraph": 2821,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 278,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "khandhaka",
+                        "vinaya",
+                        "mūla",
+                        "pāḷi",
+                        "cūḷavagga"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 2821,
+                    "book_name": "vin4"
+                }
+            ]
+        },
+        "217": {
+            "max_paragraph": 3645,
+            "name_source": "wbw_book_tag",
+            "file_types": [
+                {
+                    "book_id": 279,
+                    "from_paragraph": 3,
+                    "type": "mula",
+                    "tags": [
+                        "pāḷi",
+                        "mūla",
+                        "vinaya",
+                        "parivāra"
+                    ]
+                }
+            ],
+            "segments": [
+                {
+                    "para_from": 3,
+                    "para_to": 3645,
+                    "book_name": "vin5"
+                }
+            ]
+        }
+    },
+    "overrides": {
+        "107": {
+            "reason": "旧表把 book 107(apadāna-aṭṭhakathā)切成 kn10_A(para 3-2141)与 kn10_B(para 2142-3875),并声称后者对应 therī。实测标题证伪:para 2146 的标题是「(Dutiyo bhāgo) Therāpadānaṃ」——那是 therāpadāna 的第二卷而非 therīapadāna;全书只有一个 level-1 标题「Apadāna-aṭṭhakathā」,vagga 编到 56(Yasavaggo)也正是 therāpadāna 的范围,书内无任何 therī 标题。therīapadāna 另在 book 144 para 6534 起(level-1「Therīapadānapāḷi」,wbw 标记 kn11@6532)。故 book 107 整本归 kn10,与 mūla 侧 books 143/144 的 kn10 对齐。",
+            "segments": [
+                {
+                    "para_from": 1,
+                    "para_to": 999999,
+                    "book_name": "kn10"
+                }
+            ]
+        }
+    }
+}

+ 264 - 0
api-v13/scripts/related/build_book_config.php

@@ -0,0 +1,264 @@
+<?php
+
+/**
+ * 生成书级配置表 book_config.json:每本 VRI 文件的类型(mūla/义注/复注)与
+ * 书名分段(哪一段段落属于哪个 book_name)。
+ *
+ * 为什么需要:123 本文件的 wbw 标记里完全没有书名信息(只有裸 paraN),书名要从
+ * 别处来。证据按可信度排序:
+ *   1. wbw 的 book_tag 标记(dn1@3、an3@323)——文件自带的书界,最硬
+ *   2. wbw 的 paraN_xxx 后缀——逐段自带书名
+ *   3. 旧表的主导书名——最后兜底。旧表的错在 cs 值不在书名上,唯一例外是
+ *      kn10_A/kn10_B,而那两本恰好有 book_tag 证据,会被 1 覆盖掉。
+ *
+ * overrides 区是人工修正区,脚本不动它,每次重跑都保留。
+ *
+ * 用法:php scripts/related/build_book_config.php [--baseline=related_paragraphs_bak_20260909]
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$baseline = rp_assert_table($options['baseline'] ?? 'related_paragraphs_bak_20260909');
+$markers = $options['markers'] ?? 'rp_markers';
+$configPath = __DIR__.'/book_config.json';
+
+$log = new RpLogger('build_book_config', rp_report_dir());
+$log->info("书名兜底基线:$baseline");
+
+// 已有的人工修正区必须原样带过来,否则每次重跑都把人的判断冲掉。
+$overrides = new stdClass;
+if (file_exists($configPath)) {
+    $existing = rp_json_read($configPath)['overrides'] ?? [];
+    $overrides = $existing === [] ? new stdClass : (object) $existing;
+    $log->info('保留已有 overrides:'.count((array) $overrides).' 条');
+}
+
+// ── 文件类型:按 level-1 段落的 tag 判定,粒度是 book_id 不是 VRI 文件 ──────
+// book 207 一个文件里既有 pāḷi 又有 ṭīkā,按文件判会判错。
+$typeRows = DB::select("
+    select p.book, p.paragraph, bt.sn as book_id, string_agg(t.name, ',') as tags
+    from pali_texts p
+    join tag_maps m on m.anchor_id = p.uid and m.table_name = 'pali_texts'
+    join tags t on t.id = m.tag_id
+    left join book_titles bt on bt.book = p.book and bt.paragraph = p.paragraph
+    where p.level = 1
+    group by p.book, p.paragraph, bt.sn
+    order by p.book, p.paragraph
+");
+
+$fileTypes = [];
+foreach ($typeRows as $row) {
+    $tags = explode(',', $row->tags);
+    $type = match (true) {
+        (bool) array_intersect($tags, ['ṭīkā', 'mūlaṭīkā', 'anuṭīkā', 'abhinavaṭīkā', 'purāṇaṭīkā']) => 'tika',
+        in_array('aṭṭhakathā', $tags, true) => 'atthakatha',
+        (bool) array_intersect($tags, ['mūla', 'pāḷi']) => 'mula',
+        default => 'unknown',
+    };
+    $fileTypes[$row->book][] = [
+        'book_id' => $row->book_id,
+        'from_paragraph' => $row->paragraph,
+        'type' => $type,
+        'tags' => $tags,
+    ];
+    $log->count("file_type.$type");
+    if ($type === 'unknown') {
+        $log->unresolved('file_type_unknown', [
+            'book' => $row->book, 'paragraph' => $row->paragraph, 'tags' => $row->tags,
+        ]);
+    }
+}
+
+// ── 书名证据 ─────────────────────────────────────────────────────────────
+$books = DB::select('select distinct book from pali_texts order by book');
+$config = [];
+
+foreach ($books as $b) {
+    $book = $b->book;
+    $maxPara = (int) DB::table('pali_texts')->where('book', $book)->max('paragraph');
+
+    // 证据 1:book_tag 标记,给出文件内的书界切换点
+    $tagMarks = DB::select(
+        "select paragraph, book_name from $markers where book = ? and kind = 'book_tag' order by paragraph",
+        [$book]
+    );
+
+    // 证据 2:paraN_xxx 后缀,逐段自带书名
+    $suffixMarks = DB::select(
+        "select paragraph, book_name from $markers
+         where book = ? and kind in ('single','interval') and book_name is not null
+         order by paragraph, wid",
+        [$book]
+    );
+
+    // 证据 3:旧表逐段落的名字,按连续段压缩。
+    // 空书名也必须成段——book 177 一个文件里装了四部书,只有头一部是 abhi8,
+    // 后三部(nāmarūpaparicchedo 等)本来就没有 SC 书名。早先过滤掉空名,
+    // 结果 abhi8 越过书界铺满全文件,把 10695 行错配进了 abhi8 的注释链。
+    $oldNames = DB::select(
+        "select para, max(book_name) as book_name from $baseline where book = ?
+         group by para order by para",
+        [$book]
+    );
+
+    $source = match (true) {
+        $tagMarks !== [] => 'wbw_book_tag',
+        $suffixMarks !== [] => 'wbw_suffix',
+        $oldNames !== [] => 'old_table',
+        default => 'none',
+    };
+
+    $points = [];   // paragraph => book_name 的切换点
+    if ($source === 'wbw_book_tag') {
+        foreach ($tagMarks as $m) {
+            $points[(int) $m->paragraph] = $m->book_name;
+        }
+        // book_tag 只给书界,段内若还有后缀且与之矛盾,记下来复核
+        foreach ($suffixMarks as $m) {
+            $expected = null;
+            foreach ($points as $p => $n) {
+                if ($p <= $m->paragraph) {
+                    $expected = $n;
+                }
+            }
+            if ($expected !== null && $expected !== $m->book_name) {
+                $log->count('name_conflict.tag_vs_suffix');
+                $log->unresolved('name_conflict_tag_vs_suffix', [
+                    'book' => $book, 'paragraph' => (int) $m->paragraph,
+                    'book_tag_says' => $expected, 'suffix_says' => $m->book_name,
+                ]);
+            }
+        }
+    } elseif ($source === 'wbw_suffix') {
+        $prev = null;
+        foreach ($suffixMarks as $m) {
+            if ($m->book_name !== $prev) {
+                $points[(int) $m->paragraph] = $m->book_name;
+                $prev = $m->book_name;
+            }
+        }
+    } elseif ($source === 'old_table') {
+        $prev = null;
+        foreach ($oldNames as $m) {
+            // 序言名 dn1_A 是义注开头的正常设计,保留;其余同名连续段合并
+            if ($m->book_name !== $prev) {
+                $points[(int) $m->para] = $m->book_name;
+                $prev = $m->book_name;
+            }
+        }
+    }
+
+    // 义注/复注开头的序言段用 {book}_A 命名(dn1_A 型,全库 12 本)。wbw 里带
+    // {mula}_0 章标记的书(99/103/130/133)导出器能自己认出来,但另有 6 本
+    // (181/185/188/192 及 179/211 的文件中段)wbw 完全没有痕迹,序言范围只存在于
+    // 旧表里。这里把旧表的 _A 连续段叠加进切换点,免得序言被并进正文名下。
+    if ($source !== 'old_table') {
+        // 注意:序言段里出现 paraN_mula 标记是正常的,不能拿首个 cs 标记当序言终点。
+        // book 130 的序言(mn1_0@5)里就有 para1_mn1@40,序言真正的终点是章标记
+        // mn1_1@47;book 192 同样。序言段照旧表原样叠加即可。
+        $runName = null;
+        $runFrom = null;
+        $flushRun = function (int $endPara) use (&$points, &$runName, &$runFrom, $log, $book, $oldNames) {
+            if ($runName === null) {
+                return;
+            }
+            $base = preg_replace('/_A$/', '', $runName);
+
+            // 真序言的后面一定跟着正文(基名)。book 143 的 kn10_A 铺满整个文件、
+            // 后面根本没有 kn10——那是 E3 的错名而不是序言,绝不能叠加进来。
+            $baseFollows = false;
+            foreach ($oldNames as $row) {
+                if ((int) $row->para > $endPara && $row->book_name === $base) {
+                    $baseFollows = true;
+                    break;
+                }
+            }
+            if (! $baseFollows) {
+                $log->count('prologue_overlay.rejected');
+                $log->info("book $book 拒绝叠加 $runName@$runFrom-{$endPara}:其后无 $base 正文,判为错名而非序言");
+                $runName = null;
+                $runFrom = null;
+
+                return;
+            }
+            // 序言区间内的旧切换点要清掉:book_tag 的 dn1@3 落在 dn1_A@1-198 中间,
+            // 不清就会把序言从 para 3 截断,只剩两段。
+            $base = $points[$endPara + 1] ?? $base;
+            foreach (array_keys($points) as $existing) {
+                if ($existing > $runFrom && $existing <= $endPara) {
+                    unset($points[$existing]);
+                }
+            }
+            $points[$runFrom] = $runName;
+            if (! isset($points[$endPara + 1])) {
+                $points[$endPara + 1] = $base;
+            }
+            $log->count('prologue_overlay');
+            $log->info("book $book 叠加序言段 $runName@$runFrom-$endPara");
+            $runName = null;
+            $runFrom = null;
+        };
+        $lastPara = null;
+        foreach ($oldNames as $m) {
+            $para = (int) $m->para;
+            $isPrologue = str_ends_with((string) $m->book_name, '_A');
+            if ($isPrologue && $m->book_name === $runName && $para === $lastPara + 1) {
+                $lastPara = $para;
+
+                continue;
+            }
+            if ($runName !== null) {
+                $flushRun($lastPara);
+            }
+            if ($isPrologue) {
+                $runName = $m->book_name;
+                $runFrom = $para;
+            }
+            $lastPara = $para;
+        }
+        if ($runName !== null) {
+            $flushRun($lastPara);
+        }
+        ksort($points);
+    }
+
+    // 切换点 → 区间
+    $segments = [];
+    $keys = array_keys($points);
+    foreach ($keys as $i => $from) {
+        $segments[] = [
+            'para_from' => $from,
+            'para_to' => isset($keys[$i + 1]) ? $keys[$i + 1] - 1 : $maxPara,
+            'book_name' => $points[$from],
+        ];
+    }
+
+    $config[(string) $book] = [
+        'max_paragraph' => $maxPara,
+        'name_source' => $source,
+        'file_types' => $fileTypes[$book] ?? [],
+        'segments' => $segments,
+    ];
+    $log->count("name_source.$source");
+    if ($source === 'none') {
+        $log->unresolved('book_name_unknown', ['book' => $book]);
+    }
+    if (count($segments) > 1) {
+        $log->info(sprintf('book %-3d %-14s %d 段:%s', $book, $source, count($segments),
+            implode(' ', array_map(fn ($s) => "{$s['book_name']}@{$s['para_from']}", $segments))));
+    }
+}
+
+rp_json_write($configPath, [
+    'generated_at' => date('c'),
+    'baseline_table' => $baseline,
+    'purpose' => '每本 VRI 文件的类型与书名分段。导出器优先用 wbw 现场证据,此表只在文件本身没有书名信息时兜底。overrides 是人工修正区,重跑不覆盖。',
+    'books' => $config,
+    'overrides' => $overrides,
+]);
+$log->info("配置表:{$configPath}(".count($config).' 本)');
+
+$log->finish();

+ 129 - 0
api-v13/scripts/related/build_markers.php

@@ -0,0 +1,129 @@
+<?php
+
+/**
+ * 把 wbw_templates 里的 .ctl. 锚点解析成工作表 rp_markers。
+ *
+ * 导出器和检测器都要按标记做集合运算,逐次在 PHP 里重解析 33 万行既慢又容易两边
+ * 规则跑偏,所以物化一次、共用一份。改了 MarkerParser 就要重跑这个脚本。
+ *
+ * 用法:php scripts/related/build_markers.php [--table=rp_markers]
+ */
+
+require __DIR__.'/lib/boot.php';
+require __DIR__.'/lib/MarkerParser.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$table = $options['table'] ?? 'rp_markers';
+if (! preg_match('/^rp_[a-z0-9_]+$/', $table)) {
+    throw new InvalidArgumentException("工作表名必须以 rp_ 开头:$table");
+}
+
+$log = new RpLogger('build_markers', rp_report_dir());
+$log->info("目标工作表:$table");
+
+DB::statement("drop table if exists $table");
+DB::statement("
+    create table $table (
+        book        integer not null,
+        paragraph   integer not null,
+        wid         integer not null,
+        word        varchar(1024) not null,
+        kind        varchar(16) not null,
+        book_name   varchar(64),
+        cs_from     integer,
+        cs_to       integer,
+        cs_count    integer not null default 0,
+        numbers     varchar(64),
+        is_abbrev   boolean not null default false,
+        repaired    text,
+        error       text
+    )
+");
+
+$total = DB::table('wbw_templates')->where('type', '.ctl.')->where('style', '#a#')->count();
+$log->info("待解析锚点:$total 行");
+
+$buffer = [];
+$written = 0;
+
+$flush = function () use (&$buffer, &$written, $table, $log) {
+    if ($buffer === []) {
+        return;
+    }
+    DB::table($table)->insert($buffer);
+    $written += count($buffer);
+    $buffer = [];
+    if ($written % 50000 === 0) {
+        $log->info("  已写入 $written 行");
+    }
+};
+
+DB::table('wbw_templates')
+    ->where('type', '.ctl.')
+    ->where('style', '#a#')
+    ->select('book', 'paragraph', 'wid', 'word')
+    ->orderBy('book')->orderBy('paragraph')->orderBy('wid')
+    ->chunk(20000, function ($chunk) use (&$buffer, $flush, $log) {
+        foreach ($chunk as $row) {
+            $parsed = MarkerParser::parse($row->word);
+            $log->count('kind.'.$parsed['kind']);
+
+            // 缩写区间:右端位数少于左端,正是旧生成器翻车的那一类,单独打标以便统计。
+            $isAbbrev = false;
+            if ($parsed['kind'] === MarkerParser::KIND_INTERVAL
+                && preg_match('/^para([0-9]+)-([0-9]+)/', $row->word, $m)
+                && strlen($m[2]) < strlen($m[1])) {
+                $isAbbrev = true;
+                $log->count('interval.abbrev');
+            }
+
+            if ($parsed['error']) {
+                $log->unresolved('marker_parse_failed', [
+                    'book' => $row->book, 'paragraph' => $row->paragraph,
+                    'word' => $row->word, 'detail' => $parsed['error'],
+                ]);
+            }
+            if ($parsed['repaired']) {
+                $log->warn("修补标记 book={$row->book} para={$row->paragraph}: {$parsed['repaired']}");
+                $log->unresolved('marker_repaired', [
+                    'book' => $row->book, 'paragraph' => $row->paragraph,
+                    'word' => $row->word, 'detail' => $parsed['repaired'],
+                ]);
+            }
+
+            $buffer[] = [
+                'book' => $row->book,
+                'paragraph' => $row->paragraph,
+                'wid' => $row->wid,
+                'word' => $row->word,
+                'kind' => $parsed['kind'],
+                'book_name' => $parsed['book_name'],
+                'cs_from' => $parsed['cs'] === [] ? null : $parsed['cs'][0],
+                'cs_to' => $parsed['cs'] === [] ? null : end($parsed['cs']),
+                'cs_count' => count($parsed['cs']),
+                'numbers' => $parsed['numbers'] ? implode('.', $parsed['numbers']) : null,
+                'is_abbrev' => $isAbbrev,
+                'repaired' => $parsed['repaired'],
+                'error' => $parsed['error'],
+            ];
+            if (count($buffer) >= 5000) {
+                $flush();
+            }
+        }
+    });
+$flush();
+
+$log->info("写入完成:$written 行");
+if ($written !== $total) {
+    $log->error("行数不符:源 $total vs 写入 $written");
+}
+
+$log->info('建索引中…');
+DB::statement("create index on $table (book, paragraph)");
+DB::statement("create index on $table (kind)");
+DB::statement("create index on $table (book_name)");
+DB::statement("create index on $table (is_abbrev) where is_abbrev");
+
+$log->finish();

+ 385 - 0
api-v13/scripts/related/check.php

@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * related_paragraphs 记分卡:按 known_issues.json 的探测器给任意一张 related 表打分。
+ *
+ * 这是整个重建工程的标尺——每一轮「导出 → 检测 → 交给模型评估 → 改规则」都靠它
+ * 回答两个问题:错误变少了没有?本来正确的书有没有被搞坏?
+ *
+ * 用法:
+ *   php scripts/related/check.php --table=related_paragraphs_bak_20260909 --save-baseline
+ *   php scripts/related/check.php --table=related_paragraphs_v1
+ *
+ * 依赖 rp_markers(先跑 build_markers.php)。
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$table = rp_assert_table($options['table'] ?? 'related_paragraphs');
+$markers = $options['markers'] ?? 'rp_markers';
+$saveBaseline = isset($options['save-baseline']);
+
+$known = rp_json_read(__DIR__.'/known_issues.json');
+$params = $known['params'];
+$log = new RpLogger('check.'.$table, rp_report_dir());
+$log->info("被检表:$table");
+$log->info("标记表:$markers");
+
+$one = fn (string $sql, array $bind = []) => (array) DB::selectOne($sql, $bind);
+$all = fn (string $sql, array $bind = []) => array_map(fn ($r) => (array) $r, DB::select($sql, $bind));
+
+$results = [];
+
+/** 记一条探测结果,并与 known_issues.json 的基线对照。 */
+$record = function (string $id, array $measured, ?string $note = null) use (&$results, $known, $log) {
+    $spec = null;
+    foreach ($known['detectors'] as $d) {
+        if ($d['id'] === $id) {
+            $spec = $d;
+            break;
+        }
+    }
+    $results[$id] = [
+        'title' => $spec['title'] ?? $id,
+        'severity' => $spec['severity'] ?? 'unknown',
+        'baseline' => $spec['baseline'] ?? null,
+        'target_v1' => $spec['target_v1'] ?? null,
+        'measured' => $measured,
+        'note' => $note,
+    ];
+    $log->info(sprintf('[%-24s] %s', $id, json_encode($measured, JSON_UNESCAPED_UNICODE)));
+    if ($note) {
+        $log->info('  '.$note);
+    }
+};
+
+// ── E1 cs 乱码值 ──────────────────────────────────────────────────────────
+$threshold = $params['cs_garbage_threshold'];
+$record('E1_cs_garbage', $one(
+    "select count(*)::int as rows, count(distinct book)::int as books from $table where cs_para > ?",
+    [$threshold]
+));
+
+// ── E2 章回绕:同 (book, book_name) 内 cs 从大值回到 1 ────────────────────
+// 必须按段落级 cs_min 判,不能逐行比。区间标记展开后一个段落有多行(para1-2 展开
+// 成 cs=1、cs=2 两行),连续这样的段落逐行看就是 …2,1,2,1… ——每段都像一次重置。
+// book 137 的 sn5「5 次回绕」、book 108 的 kn12「95 次回绕」都是这么来的假象。
+$record('E2_chapter_wrap', $one("
+    with p as (
+        select book, book_name, para, min(cs_para) as cs_min
+        from {$table} where cs_para > 0 and book_name <> ''
+        group by book, book_name, para
+    ),
+    s as (
+        select book, book_name, para, cs_min,
+               lag(cs_min) over (partition by book, book_name order by para) as prev_min
+        from p
+    )
+    select count(*)::int as wrap_points, count(distinct book)::int as books
+    from s where cs_min = 1 and prev_min > 1
+"));
+
+// ── E3 kn10 家族 ─────────────────────────────────────────────────────────
+$record('E3_kn10_missing', $one("
+    select
+        count(*) filter (where book_name = 'kn10')::int   as kn10_rows,
+        count(*) filter (where book_name = 'kn10_A')::int as kn10_a_rows,
+        count(*) filter (where book_name = 'kn10_B')::int as kn10_b_rows
+    from $table
+"));
+
+// ── E4 空 book_name(预期保留) ───────────────────────────────────────────
+$record('E4_empty_book_name', $one(
+    "select count(*)::int as rows, count(distinct book)::int as books from $table where book_name = ''"
+));
+
+// ── E5 book_id 未赋值 ────────────────────────────────────────────────────
+$record('E5_book_id_zero', $one(
+    "select count(*)::int as rows, count(distinct book)::int as books from $table where book_id = 0"
+));
+
+// ── E6 覆盖缺口:wbw 有这个段落,related 没有任何行 ────────────────────────
+$record('E6_coverage_gap', $one("
+    with wbw as (select distinct book, paragraph from pali_texts),
+         rel as (select distinct book, para from $table)
+    select count(*)::int as segments, count(distinct w.book)::int as books
+    from wbw w left join rel r on r.book = w.book and r.para = w.paragraph
+    where r.book is null
+"));
+
+// ── E7 缩写区间:旧生成器在这里丢段或产废值 ────────────────────────────────
+$record('E7_abbrev_interval_lost', $one("
+    with seg as (select distinct book, paragraph from $markers where is_abbrev),
+         hit as (
+            select s.book, s.paragraph,
+                   count(r.id)::int as rows,
+                   count(r.id) filter (where r.cs_para > $threshold)::int as garbage
+            from seg s left join $table r on r.book = s.book and r.para = s.paragraph
+            group by 1, 2
+         )
+    select
+        count(*)::int as marker_segments,
+        count(distinct book)::int as books,
+        count(*) filter (where rows = 0)::int as segments_without_rows,
+        count(*) filter (where rows > 0 and garbage > 0)::int as segments_with_garbage
+    from hit
+"));
+
+// ── E8 书边界污染平铺 ─────────────────────────────────────────────────────
+// 污染的准确签名是「整段一个 cs 标记都没有,却被写进了非零 cs」——那个值只能是
+// 从上一本沿用下来的。早先按「cs 值种类少、行数多」判会把章回绕误判成污染
+// (book 152 有 516 个标记却只 24 个 cs 值,那是 22 次回绕),按标记判才分得开。
+// cs 恒为 0 的整段不算污染:0 是「未赋值」,不是编造出来的值。
+$flat = $all("
+    with seg as (
+        select bt.book, bt.sn as book_id, bt.paragraph as p_from,
+               coalesce(lead(bt.paragraph) over (partition by bt.book order by bt.paragraph) - 1, 2147483647) as p_to
+        from book_titles bt
+    ),
+    book_marks as (
+        select book, count(*) as n from $markers where kind in ('single','interval') group by 1
+    )
+    select s.book, s.book_id, s.p_from, x.rows, x.max_cs, x.vals
+    from seg s
+    join book_marks bm on bm.book = s.book
+    cross join lateral (
+        select count(*)::int as rows, coalesce(max(cs_para), 0)::int as max_cs,
+               count(distinct cs_para)::int as vals
+        from $table r where r.book = s.book and r.para between s.p_from and s.p_to
+    ) x
+    where x.rows > 0 and x.max_cs > 0
+      and not exists (
+        select 1 from $markers m
+        where m.book = s.book and m.paragraph between s.p_from and s.p_to
+          and m.kind in ('single','interval')
+      )
+    order by x.rows desc
+");
+$record('E8_flat_pollution', [
+    'groups' => count($flat),
+    'rows' => array_sum(array_column($flat, 'rows')),
+], $flat === [] ? null : '污染段:'.json_encode($flat, JSON_UNESCAPED_UNICODE));
+
+// ── E9 全书无标记:related 有行但 wbw 无 para 标记 ─────────────────────────
+$noMarker = $all("
+    with rel as (select book, count(*)::int as rows from $table group by 1),
+         mk  as (select book, count(*)::int as markers from $markers
+                 where kind in ('single', 'interval') group by 1)
+    select rel.book, rel.rows from rel left join mk on mk.book = rel.book
+    where coalesce(mk.markers, 0) = 0 order by rel.book
+");
+$record('E9_no_marker_books', [
+    'books' => count($noMarker),
+    'book_list' => array_column($noMarker, 'book'),
+], $noMarker === [] ? null : '各本行数:'.json_encode($noMarker, JSON_UNESCAPED_UNICODE));
+
+// ── E10 自造名(预期保留) ────────────────────────────────────────────────
+$record('E10_selfmade_names', $one("
+    select
+        count(*) filter (where book_name = 'NK')::int   as nk_rows,
+        count(*) filter (where book_name like 'subo%')::int as subo_rows,
+        count(*) filter (where book_name = 'dict')::int as dict_rows
+    from $table
+"));
+
+// ── D 连续性:同 (book, book_name, cs_para) 的 para 应构成连续区间 ──────────
+$record('D_continuity', $one("
+    with g as (
+        select book, book_name, cs_para, para,
+               para - row_number() over (partition by book, book_name, cs_para order by para) as grp
+        from $table where cs_para > 0 and book_name <> ''
+    ), seg as (
+        select book, book_name, cs_para, count(distinct grp)::int as segments
+        from g group by 1, 2, 3
+    )
+    select count(*)::int as broken_groups, count(distinct book)::int as books,
+           coalesce(sum(segments - 1), 0)::int as extra_segments
+    from seg where segments > 1
+"));
+
+// ── D 镜像对齐:注释链条两侧同名书的 cs 上界应一致 ─────────────────────────
+$watch = ['dn1', 'kn6', 'kn9', 'abhi5', 'abhi3', 'abhi4', 'abhi6', 'abhi7'];
+$mirror = [];
+foreach ($watch as $name) {
+    // 必须排除乱码值:旧表里 abhi4/5/6/7 的 max 全是六位废值(44022 等),
+    // 不滤掉就看不出真实的跨侧对齐情况。
+    $perFile = $all(
+        "select book, max(cs_para)::int as max_cs, count(*)::int as rows
+         from $table where book_name = ? and cs_para <= ? group by 1 order by 1",
+        [$name, $threshold]
+    );
+    $mirror[$name] = [
+        'overall_max' => $perFile === [] ? null : max(array_column($perFile, 'max_cs')),
+        'per_file' => $perFile,
+    ];
+}
+$aligned = $known['detectors'];
+$expectedMax = [];
+foreach ($aligned as $d) {
+    if ($d['id'] === 'D_mirror_alignment') {
+        $expectedMax = $d['baseline']['aligned'];
+    }
+}
+$deviations = [];
+foreach ($expectedMax as $name => $expected) {
+    if (($mirror[$name]['overall_max'] ?? null) !== $expected) {
+        $deviations[$name] = ['expected' => $expected, 'actual' => $mirror[$name]['overall_max'] ?? null];
+    }
+}
+$record('D_mirror_alignment', [
+    'deviations' => count($deviations),
+    'detail' => $deviations,
+], '各名 max(cs_para):'.json_encode(
+    array_map(fn ($m) => $m['overall_max'], $mirror),
+    JSON_UNESCAPED_UNICODE
+));
+$results['D_mirror_alignment']['per_file'] = $mirror;
+
+// ── D 区间展开:区间标记的展开行数必须等于 cs_to − cs_from + 1 ──────────────
+$record('D_interval_expansion', $one("
+    with mk as (
+        select book, paragraph, min(cs_from)::int as cs_from, max(cs_to)::int as cs_to,
+               max(cs_to) - min(cs_from) + 1 as expect
+        from $markers where kind = 'interval' group by 1, 2
+    ), got as (
+        select mk.book, mk.paragraph, mk.expect,
+               count(distinct r.cs_para)::int as actual
+        from mk left join $table r on r.book = mk.book and r.para = mk.paragraph
+             and r.cs_para between mk.cs_from and mk.cs_to
+        group by 1, 2, 3
+    )
+    select count(*)::int as interval_markers,
+           count(*) filter (where actual <> expect)::int as mismatched_markers,
+           count(*) filter (where actual = 0)::int as empty_markers
+    from got
+"));
+
+// ── D 配对质量:章后缀方案到底有没有帮上忙,只有这把尺子能回答 ────────────
+// index() 拿 (book_name, cs_para) 全表取行。回绕让同一个 key 在几十个章里重复,
+// 一次查询就把几十章的段落全捞回来——召回没问题,精度崩了。所以要同时看两头:
+//   可信配对:key 跨文件命中、且在任何单本书里都不超过 10 段——这才是真配对。
+//     直接数 rows_paired 会把回绕造成的噪声算成资产(kn10:1 在 56 个章里重复,
+//     一次查询捞回上千段,那不是配对)。加对章后缀时可信配对会涨,加错才会掉。
+//   膨胀键:某本书里命中超过 10 / 30 段的 key,回绕的直接症状
+$record('D_pairing', $one("
+    with per_book as (
+        select book_name, cs_para, book, count(distinct para)::int as paras
+        from {$table} where cs_para > 0 and book_name <> ''
+        group by book_name, cs_para, book
+    ),
+    k as (
+        select book_name, cs_para, count(*)::int as books,
+               sum(paras)::int as rows, max(paras)::int as max_paras
+        from per_book group by book_name, cs_para
+    )
+    select
+        count(*)::int                                            as keys,
+        count(*) filter (where books >= 2)::int                  as keys_cross_book,
+        sum(rows) filter (where books >= 2)::int                 as rows_paired,
+        sum(rows) filter (where books >= 2 and max_paras <= 10)::int as rows_paired_trusted,
+        sum(rows)::int                                           as rows_total,
+        round(avg(books), 3)::float                              as mean_books_per_key,
+        count(*) filter (where max_paras > 10)::int              as keys_bloated,
+        count(*) filter (where max_paras > 30)::int              as keys_bloated_bad,
+        max(max_paras)::int                                      as worst_paras_in_one_book
+    from k
+"));
+
+// ── 逐本记分卡:把 book 级错误信号汇总,零信号的书即基线冻结对象 ─────────────
+$log->info('生成逐本记分卡…');
+$scorecard = $all("
+    with rel as (
+        select book,
+               count(*)::int as rows,
+               count(distinct book_name)::int as names,
+               count(*) filter (where cs_para > $threshold)::int as garbage_rows,
+               count(*) filter (where book_id = 0)::int as no_book_id_rows,
+               count(*) filter (where book_name = '')::int as empty_name_rows
+        from $table group by 1
+    ),
+    wrap as (
+        select book, count(*)::int as wrap_points from (
+            select book, book_name, para, min(cs_para) as cs_min,
+                   lag(min(cs_para)) over (partition by book, book_name order by para) as prev_min
+            from {$table} where cs_para > 0 and book_name <> ''
+            group by book, book_name, para
+        ) s where cs_min = 1 and prev_min > 1 group by 1
+    ),
+    abbrev as (
+        select s.book, count(*) filter (where h.rows = 0)::int as abbrev_lost from (
+            select distinct book, paragraph from $markers where is_abbrev
+        ) s join lateral (
+            select count(r.id)::int as rows from $table r where r.book = s.book and r.para = s.paragraph
+        ) h on true group by 1
+    ),
+    gap as (
+        select w.book, count(*)::int as gap_segments
+        from (select distinct book, paragraph from wbw_templates) w
+        left join (select distinct book, para from $table) r on r.book = w.book and r.para = w.paragraph
+        where r.book is null group by 1
+    )
+    select rel.book, rel.rows, rel.names, rel.garbage_rows, rel.no_book_id_rows, rel.empty_name_rows,
+           coalesce(wrap.wrap_points, 0) as wrap_points,
+           coalesce(abbrev.abbrev_lost, 0) as abbrev_lost,
+           coalesce(gap.gap_segments, 0) as gap_segments
+    from rel
+    left join wrap on wrap.book = rel.book
+    left join abbrev on abbrev.book = rel.book
+    left join gap on gap.book = rel.book
+    order by rel.book
+");
+
+$flatBooks = [];
+foreach ($flat as $f) {
+    $flatBooks[$f['book']] = ($flatBooks[$f['book']] ?? 0) + 1;
+}
+$clean = [];
+$dirty = [];
+foreach ($scorecard as &$row) {
+    $row['flat_groups'] = $flatBooks[$row['book']] ?? 0;
+    // 空 book_name 是 E4 的预期状态,不算错误信号;其余四类算。
+    $row['signals'] = $row['garbage_rows'] + $row['wrap_points']
+        + $row['abbrev_lost'] + $row['flat_groups'] + $row['gap_segments'];
+    if ($row['signals'] === 0) {
+        $clean[] = $row['book'];
+    } else {
+        $dirty[] = $row['book'];
+    }
+}
+unset($row);
+
+$log->info(sprintf('逐本记分:合格 %d 本,有信号 %d 本,共 %d 本',
+    count($clean), count($dirty), count($scorecard)));
+
+$summary = [
+    'checked_at' => date('c'),
+    'database' => DB::connection()->getDatabaseName(),
+    'table' => $table,
+    'markers_table' => $markers,
+    'total_rows' => DB::table($table)->count(),
+    'detectors' => $results,
+    'books' => ['clean' => $clean, 'dirty' => $dirty, 'scorecard' => $scorecard],
+];
+
+$reportPath = rp_report_dir()."/check.$table.json";
+rp_json_write($reportPath, $summary);
+$log->info("报告:$reportPath");
+
+if ($saveBaseline) {
+    $baselinePath = __DIR__.'/baseline.json';
+    rp_json_write($baselinePath, [
+        'frozen_at' => date('c'),
+        'source_table' => $table,
+        'database' => DB::connection()->getDatabaseName(),
+        'purpose' => '旧表的实测基线。clean_books 是零错误信号的书,重建后这些书一本都不许掉出来;detectors 是各探测器的旧表读数,用于回答「错误是否减少」。',
+        'clean_books' => $clean,
+        'detectors' => array_map(fn ($r) => $r['measured'], $results),
+        'scorecard' => $scorecard,
+    ]);
+    $log->info("基线已冻结:$baselinePath");
+}
+
+$log->finish();

+ 133 - 0
api-v13/scripts/related/diff.php

@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * 两张 related 表的逐段落差异报告。
+ *
+ * 迭代的收敛判据是「每一条 diff 都能归因」——要么是修好了,要么是已知留空,不允许
+ * 有说不清来源的差异。所以这里不只给总数,还按类型分桶并各留样本,供逐轮核对。
+ *
+ * 用法:
+ *   php scripts/related/diff.php --old=related_paragraphs_bak_20260909 --new=related_paragraphs_v1
+ *   php scripts/related/diff.php --new=related_paragraphs_v1 --book=98 --samples=40
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$old = rp_assert_table($options['old'] ?? 'related_paragraphs_bak_20260909');
+$new = rp_assert_table($options['new'] ?? 'related_paragraphs_v1');
+$sampleLimit = (int) ($options['samples'] ?? 15);
+$onlyBooks = isset($options['book']) ? array_map('intval', explode(',', $options['book'])) : null;
+
+$log = new RpLogger('diff', rp_report_dir());
+$log->info("旧:$old");
+$log->info("新:$new");
+
+$bookFilter = $onlyBooks ? 'and book in ('.implode(',', $onlyBooks).')' : '';
+$log->info('比对范围:'.($onlyBooks ? implode(',', $onlyBooks) : '全库'));
+
+// 每个 (book, para) 压成一行「书名:cs 列表」的签名,逐段落比对。
+$sql = "
+    with o as (
+        select book, para,
+               string_agg(distinct book_name || ':' || cs_para, ',' order by book_name || ':' || cs_para) as sig,
+               count(*) as rows
+        from $old where true $bookFilter group by book, para
+    ),
+    n as (
+        select book, para,
+               string_agg(distinct book_name || ':' || cs_para, ',' order by book_name || ':' || cs_para) as sig,
+               count(*) as rows
+        from $new where true $bookFilter group by book, para
+    )
+    select
+        coalesce(o.book, n.book) as book,
+        coalesce(o.para, n.para) as para,
+        o.sig as old_sig, n.sig as new_sig,
+        coalesce(o.rows, 0) as old_rows, coalesce(n.rows, 0) as new_rows,
+        case
+            when o.book is null then 'only_in_new'
+            when n.book is null then 'only_in_old'
+            when o.sig = n.sig then 'same'
+            else 'changed'
+        end as verdict
+    from o full outer join n on n.book = o.book and n.para = o.para
+";
+
+$log->info('比对中…');
+$buckets = [];
+$samples = [];
+$perBook = [];
+$total = 0;
+
+foreach (DB::cursor($sql) as $row) {
+    $total++;
+    $verdict = $row->verdict;
+
+    if ($verdict === 'changed') {
+        // 细分:只是 cs 变了,还是书名也变了
+        $oldNames = [];
+        $newNames = [];
+        foreach (explode(',', (string) $row->old_sig) as $pair) {
+            $oldNames[substr($pair, 0, strrpos($pair, ':'))] = true;
+        }
+        foreach (explode(',', (string) $row->new_sig) as $pair) {
+            $newNames[substr($pair, 0, strrpos($pair, ':'))] = true;
+        }
+        $verdict = array_keys($oldNames) === array_keys($newNames) ? 'cs_changed' : 'name_changed';
+    }
+
+    $buckets[$verdict] = ($buckets[$verdict] ?? 0) + 1;
+    if ($verdict !== 'same') {
+        $perBook[$row->book][$verdict] = ($perBook[$row->book][$verdict] ?? 0) + 1;
+        if (count($samples[$verdict] ?? []) < $sampleLimit) {
+            $samples[$verdict][] = [
+                'book' => (int) $row->book, 'para' => (int) $row->para,
+                'old' => $row->old_sig, 'new' => $row->new_sig,
+            ];
+        }
+    }
+}
+
+ksort($buckets);
+$log->info('---- 差异分桶(按段落计) ----');
+foreach ($buckets as $verdict => $n) {
+    $log->info(sprintf('  %-14s %8d  %5.1f%%', $verdict, $n, $total ? $n / $total * 100 : 0));
+}
+
+foreach ($samples as $verdict => $items) {
+    $log->info("---- $verdict 样本 ----");
+    foreach ($items as $s) {
+        $log->info(sprintf('  book %-3d para %-6d 旧[%s] → 新[%s]',
+            $s['book'], $s['para'], $s['old'] ?? '—', $s['new'] ?? '—'));
+    }
+}
+
+// 差异最集中的书优先看
+$ranked = [];
+foreach ($perBook as $book => $b) {
+    $ranked[] = ['book' => (int) $book, 'total' => array_sum($b)] + $b;
+}
+usort($ranked, fn ($a, $b) => $b['total'] <=> $a['total']);
+
+$log->info('---- 差异最多的 20 本 ----');
+foreach (array_slice($ranked, 0, 20) as $r) {
+    $log->info(sprintf('  book %-3d 共 %-6d  %s', $r['book'], $r['total'],
+        json_encode(array_diff_key($r, ['book' => 1, 'total' => 1]), JSON_UNESCAPED_UNICODE)));
+}
+
+$path = rp_report_dir()."/diff.$new.json";
+rp_json_write($path, [
+    'generated_at' => date('c'),
+    'old_table' => $old, 'new_table' => $new,
+    'scope' => $onlyBooks ?? 'all',
+    'paragraphs_compared' => $total,
+    'buckets' => $buckets,
+    'per_book' => $ranked,
+    'samples' => $samples,
+]);
+$log->info("报告:$path");
+
+$log->finish();

+ 316 - 0
api-v13/scripts/related/export.php

@@ -0,0 +1,316 @@
+<?php
+
+/**
+ * 从 wbw_templates 的锚点标记重放 related_paragraphs 第一版。
+ *
+ * 原则是「查不到优于查到错」:任何一处判不定就留空、记 issue,绝不沿用上一个 cs 值。
+ * 旧生成链路(VRI html → cs6_para.csv → laravel import)翻车的地方全在这条原则上:
+ * 换书后无标记就把上一个 cs 一路铺下去(E8),缩写区间不认识就跳过或写成六位废值
+ * (E1/E7),倒序区间 begin>end 让导入的 for 循环空转(book 103 para 1464 的成因)。
+ *
+ * 本版不处理章回绕后缀(E2),那要看标题层级,留给下一批;先把确定性规则跑干净,
+ * 混在一起会看不出是哪条规则错了。
+ *
+ * 用法:
+ *   php scripts/related/export.php --to=related_paragraphs_v1
+ *   php scripts/related/export.php --to=related_paragraphs_v1 --book=136,98,207   # 样例验货
+ */
+
+require __DIR__.'/lib/boot.php';
+
+use Illuminate\Support\Facades\DB;
+
+[$options] = rp_args($argv);
+$target = rp_assert_table($options['to'] ?? 'related_paragraphs_v1');
+$markersTable = $options['markers'] ?? 'rp_markers';
+$onlyBooks = isset($options['book']) ? array_map('intval', explode(',', $options['book'])) : null;
+
+$log = new RpLogger('export', rp_report_dir());
+$log->info("目标表:$target");
+if ($onlyBooks) {
+    $log->info('只导出:'.implode(',', $onlyBooks));
+}
+
+$config = rp_json_read(__DIR__.'/book_config.json');
+$bookConfig = $config['books'];
+$overrides = $config['overrides'] ?? [];
+
+// ── 建表 ─────────────────────────────────────────────────────────────────
+if (! $onlyBooks) {
+    DB::statement("drop table if exists $target");
+}
+DB::statement("
+    create table if not exists $target (
+        id bigserial primary key,
+        book integer not null,
+        para integer not null,
+        book_id integer not null,
+        cs_para integer not null,
+        book_name varchar(64) not null,
+        created_at timestamp(0), updated_at timestamp(0)
+    )
+");
+if ($onlyBooks) {
+    DB::table($target)->whereIn('book', $onlyBooks)->delete();
+}
+
+// ── 预载 ─────────────────────────────────────────────────────────────────
+$log->info('预载 book_titles…');
+$titles = [];
+foreach (DB::select('select book, paragraph, sn from book_titles order by book, paragraph') as $t) {
+    $titles[$t->book][] = ['paragraph' => (int) $t->paragraph, 'sn' => (int) $t->sn];
+}
+
+$books = array_map(
+    fn ($r) => (int) $r->book,
+    DB::select('select distinct book from pali_texts order by book')
+);
+if ($onlyBooks) {
+    $books = array_values(array_intersect($books, $onlyBooks));
+}
+$log->info('待导出文件数:'.count($books));
+
+$buffer = [];
+$written = 0;
+$now = date('Y-m-d H:i:s');
+
+$flush = function () use (&$buffer, &$written, $target) {
+    if ($buffer === []) {
+        return;
+    }
+    foreach (array_chunk($buffer, 5000) as $chunk) {
+        DB::table($target)->insert($chunk);
+    }
+    $written += count($buffer);
+    $buffer = [];
+};
+
+/** 在配置分段里查某段落该用什么书名;段落早于首段时沿用首段的名。 */
+$configName = function (int $book, int $para) use ($bookConfig, $overrides): ?string {
+    // overrides 是人工判定区,优先级高于自动推导出来的分段。
+    $segments = $overrides[(string) $book]['segments']
+        ?? $bookConfig[(string) $book]['segments']
+        ?? [];
+    if ($segments === []) {
+        return null;
+    }
+    $name = $segments[0]['book_name'];
+    foreach ($segments as $s) {
+        if ($para >= $s['para_from']) {
+            $name = $s['book_name'];
+        }
+    }
+
+    return $name;
+};
+
+foreach ($books as $book) {
+    $bookTitles = $titles[$book] ?? [];
+
+    // 段落全集取 pali_texts 而不是 wbw_templates:pali_texts 是严格超集
+    // (523284 段 vs 516113 段),wbw 少的那 7171 段散在 21 本里,
+    // 按 wbw 取全集会白丢这些段落的行。wbw 只负责提供标记。
+    $paragraphs = array_map(
+        fn ($r) => (int) $r->paragraph,
+        DB::select('select distinct paragraph from pali_texts where book = ? order by paragraph', [$book])
+    );
+    if ($paragraphs === []) {
+        continue;
+    }
+
+    $markerRows = DB::select(
+        "select paragraph, wid, word, kind, book_name, cs_from, cs_to, numbers, error
+         from $markersTable where book = ? and kind <> 'page' order by paragraph, wid",
+        [$book]
+    );
+    $byParagraph = [];
+    foreach ($markerRows as $m) {
+        $byParagraph[(int) $m->paragraph][] = $m;
+    }
+
+    // ── book_id 分段:book_titles 的每个条目开一段,之前的段落是书前页 ────────
+    $segments = [];
+    if ($bookTitles === []) {
+        $segments[] = ['sn' => 0, 'from' => 1, 'to' => PHP_INT_MAX];
+    } else {
+        if ($bookTitles[0]['paragraph'] > 1) {
+            $segments[] = ['sn' => 0, 'from' => 1, 'to' => $bookTitles[0]['paragraph'] - 1];
+        }
+        foreach ($bookTitles as $i => $t) {
+            $segments[] = [
+                'sn' => $t['sn'],
+                'from' => $t['paragraph'],
+                'to' => $bookTitles[$i + 1]['paragraph'] ?? PHP_INT_MAX,
+            ];
+            if (isset($bookTitles[$i + 1])) {
+                $segments[count($segments) - 1]['to'] = $bookTitles[$i + 1]['paragraph'] - 1;
+            }
+        }
+    }
+
+    $bookName = null;
+    $prologue = false;
+
+    // 义注文件的开头几段(书前页)在 {mula}_0 序言标记之前,但内容上属于序言。
+    // 文件里首个章标记是 _0 时,起手就用 {mula}_A,免得前几段挂到正文名下。
+    foreach ($markerRows as $m) {
+        if ($m->kind === 'chapter') {
+            if ($m->numbers === '0') {
+                $bookName = $m->book_name.'_A';
+                $prologue = true;
+                $log->count('event.prologue_seeded');
+            }
+            break;
+        }
+    }
+    // 文件自身没有任何书名标记时,书名只能全程由配置表分段决定。
+    // 配置表在所有书里都当书名基线:它已经把 book_tag 书界、人工 override 和
+    // 序言段(dn1_A 型)合并成一份完整分段。标记仍然可以就地覆盖——paraN_xxx 后缀
+    // 是最贴身的证据,book_tag 是书界事件,两者都在下面的标记循环里生效。
+    $nameFromConfig = true;
+
+    foreach ($segments as $seg) {
+        $segParagraphs = array_values(array_filter(
+            $paragraphs,
+            fn ($p) => $p >= $seg['from'] && $p <= $seg['to']
+        ));
+        if ($segParagraphs === []) {
+            continue;
+        }
+
+        // ⭐ 防污染核心规则:整段没有任何 cs 标记,就不许给它任何非零 cs。
+        // 旧生成器在这里把换书前的 cs 一路铺下去,book 207 的 1499 行恒 cs=75 就是这么来的。
+        // 但也不能整段不输出:这些段落的行多半是 cs=0 的占位行(E4 的无注释体系书、
+        // 义注序言、书前页),下游 ParaInfoController 按段落取行,删掉就是白丢覆盖。
+        // 输出 cs=0 即可——index() 取锚点时要求 cs_para > 0,cs=0 行不会产生任何配对,
+        // 既保住覆盖又不编造关系。仍然记 issue,标出待 LLM 补齐的位置。
+        $segMarkerCount = 0;
+        foreach ($segParagraphs as $p) {
+            foreach ($byParagraph[$p] ?? [] as $m) {
+                if (in_array($m->kind, ['single', 'interval'], true)) {
+                    $segMarkerCount++;
+                }
+            }
+        }
+        if ($segMarkerCount === 0 && $seg['sn'] !== 0) {
+            $log->count('segment_without_markers');
+            $log->unresolved('segment_without_markers', [
+                'book' => $book, 'book_id' => $seg['sn'],
+                'para_from' => $segParagraphs[0], 'para_to' => end($segParagraphs),
+                'paragraphs' => count($segParagraphs),
+                'detail' => '整段无 cs 标记,全部输出 cs=0 占位,待补(E8/E9)',
+            ]);
+        }
+
+        // 段起点:cs 归零等待首个标记。
+        // 书名分两种来源:文件自带 book_tag/后缀标记的,交给标记驱动;没有任何现场
+        // 证据的(123 本,如 book 98 一个文件里装了 abhi3..abhi7),只能逐段落查配置表
+        // ——这类文件的书界在 wbw 里没有任何痕迹。
+        $csList = [0];
+        $bookName ??= $configName($book, $segParagraphs[0]);
+
+        foreach ($segParagraphs as $para) {
+            $skipParagraph = false;
+
+            $configNameHere = $configName($book, $para);
+            if ($nameFromConfig) {
+                $bookName = $configNameHere;
+            }
+
+            foreach ($byParagraph[$para] ?? [] as $m) {
+                switch ($m->kind) {
+                    case 'book_tag':
+                        // 文件内的书界切换(an2@1 an3@323…),新书从 cs=0 起算
+                        if ($bookName !== $m->book_name) {
+                            $log->count('event.book_switch');
+                        }
+                        $bookName = $m->book_name;
+                        $prologue = false;
+                        $csList = [0];
+                        break;
+
+                    case 'chapter':
+                        $numbers = $m->numbers === null ? [] : array_map('intval', explode('.', $m->numbers));
+                        if ($numbers === [0]) {
+                            // {mula}_0 = 义注开头的序言(Ganthārambhakathā),不对应原文段落
+                            $prologue = true;
+                            $bookName = $m->book_name.'_A';
+                            $csList = [0];
+                            $log->count('event.prologue_begin');
+                        } else {
+                            if ($prologue) {
+                                $prologue = false;
+                                $bookName = $m->book_name;
+                                $csList = [0];
+                                $log->count('event.prologue_end');
+                            }
+                            $log->count('event.chapter');
+                        }
+                        break;
+
+                    case 'single':
+                    case 'interval':
+                        // 序言段里的 paraN_mula 后缀不夺名:序言归 {mula}_A,
+                        // 后缀只说明它在注释哪一段,不表示它已经进入正文
+                        // (book 181 的 an1_A@1-138 内就有 para1_an1 起的一串)。
+                        if ($m->book_name !== null && $configNameHere !== $m->book_name.'_A') {
+                            $bookName = $m->book_name;
+                        }
+                        // cs 标记不结束序言:序言里带 paraN_mula 是正常体例
+                        // (book 130 的 mn1_0 序言内就有 para1_mn1),序言只由
+                        // {mula}_{N>0} 章标记结束。
+                        $csList = range((int) $m->cs_from, (int) $m->cs_to);
+                        $log->count($m->kind === 'interval' ? 'marker.interval' : 'marker.single');
+                        break;
+
+                    case 'truncated':
+                        // para179- 型:区间右端缺失,本段留空,上下文不变
+                        $skipParagraph = true;
+                        $log->unresolved('truncated_marker', [
+                            'book' => $book, 'paragraph' => $para, 'word' => $m->word,
+                            'detail' => $m->error ?? '区间右端缺失',
+                        ]);
+                        break;
+
+                    default:
+                        $log->count('marker.ignored.'.$m->kind);
+                }
+            }
+
+            if ($skipParagraph) {
+                continue;
+            }
+
+            if ($bookName === null) {
+                // 没有任何书名证据:E4 的无注释体系书走到这里是正常的,输出空名占位
+                $bookName = '';
+            }
+
+            foreach ($csList as $cs) {
+                $buffer[] = [
+                    'book' => $book, 'para' => $para, 'book_id' => $seg['sn'],
+                    'cs_para' => $cs, 'book_name' => $bookName,
+                    'created_at' => $now, 'updated_at' => $now,
+                ];
+            }
+            $log->count('rows.emitted', count($csList));
+        }
+    }
+
+    $flush();
+    $log->info(sprintf('book %-3d 完成,累计 %d 行', $book, $written));
+}
+
+$flush();
+$log->info("写入完成:$written 行");
+
+if (! $onlyBooks) {
+    $log->info('建索引中…');
+    DB::statement("create index on $target (book)");
+    DB::statement("create index on $target (para)");
+    DB::statement("create index on $target (book_name)");
+    DB::statement("create index on $target (book_name, cs_para)");
+    DB::statement("create index on $target (book, para, cs_para)");
+}
+
+$log->finish();

+ 390 - 0
api-v13/scripts/related/known_issues.json

@@ -0,0 +1,390 @@
+{
+  "version": 1,
+  "purpose": "related_paragraphs 重建工程的已知错误登记表:每条一个可机检的探测器,带旧表实测基线与各阶段目标。check.php 按此表给任意一张 related 表打分,用来回答『这一轮错误是不是变少了』。",
+  "doc_ref": "api-v13/documents/related-paragraphs-redesign.md",
+  "baseline_table": "related_paragraphs_bak_20260909",
+  "baseline_database": "visuddhinanda_20260311",
+  "baseline_measured_at": "2026-09-09",
+  "params": {
+    "cs_garbage_threshold": 5000,
+    "cs_observed_max_legit": 3183,
+    "flat_min_rows": 200,
+    "flat_max_distinct_ratio": 50
+  },
+  "notes": [
+    "cs6_para.csv 并未丢失(github.com/iapt-platform/clove/pali_title/cs6_para.csv,523283 行),与设计文档 §6.1 的表述不符。它是现表的来源,含全部历史错误,因此不作生成源,只作 baseline 与 book 129 的回填源。",
+    "逐本比对 csv 非零行 vs wbw 标记数:只有 book 129 是『csv 有 6580 非零行、wbw 零标记』。E9 其余 15 本 csv 里也是全零,源头就没有。",
+    "基线数字取自旧表实测,与文档 §4.3/§8 的差异已在各条 baseline_note 注明。",
+    "E8 判据在实测中收窄,详见该条 baseline_note;旧的「cs 值种类少」判法会把章回绕误报成污染。",
+    "MarkerParser 全库实跑:330267 个锚点 100% 归类,零 unknown。新发现两类文档未记录的形态——倒序区间 3 行(para504-407 / para706-608,高位笔误,按低位补齐还原为 504-507 / 706-708,已由前后邻标记验证)与多级章标记 247 行(an5_1_1 型,13 本,义注书 100-102 与 mūla 书 82-92 共用同一套编号,是跨文件章界对齐的抓手)。",
+    "para504-407 丢段的完整链路已查清:cs6_para.csv 原样写了 begin=504,end=407,旧 Laravel 命令的 for ($i=$begin; $i<=$end; $i++) 一圈没进——是导入环节静默吞掉的,不是生成环节。"
+  ],
+  "detectors": [
+    {
+      "id": "E1_cs_garbage",
+      "title": "cs 乱码值",
+      "doc_ref": "§4.3 E1",
+      "severity": "blocker",
+      "baseline": {
+        "rows": 1242,
+        "books": 24
+      },
+      "target_v1": {
+        "rows": 0
+      },
+      "target_final": {
+        "rows": 0
+      },
+      "root_cause": "旧生成器解析无后缀区间标记 para7-10 产生废值(如 44022)",
+      "fix_stage": "batch1 导出器:超值域拒绝输出 + issue"
+    },
+    {
+      "id": "E2_chapter_wrap",
+      "title": "章回绕(cs 从 1 重新计数)",
+      "doc_ref": "§4.3 E2",
+      "severity": "blocker",
+      "baseline": {
+        "wrap_points": 395,
+        "books": 64
+      },
+      "baseline_note": "原写 430、后按逐行判据实测 429,两者都偏高:区间标记展开后一个段落有多行(para1-2 展开成 cs=1、cs=2 两行),连续这样的段落逐行看就是 …2,1,2,1…,每段都像一次重置。book 137 的 sn5「5 次回绕」、book 108 的 kn12「95 次回绕」全是这么来的假象。改按段落级 cs_min 判后,旧表实测 395 处 / 64 本。",
+      "target_v1": {
+        "wrap_points": "unchanged"
+      },
+      "target_final": {
+        "wrap_points": "<50"
+      },
+      "root_cause": "VRI 标记是章内局部编号,章界处重置,旧生成器照搬",
+      "fix_stage": "batch3 章后缀;v1 不处理,先让确定性规则跑干净"
+    },
+    {
+      "id": "E3_kn10_missing",
+      "title": "kn10 家族命名错乱,apadāna 注释链断裂",
+      "doc_ref": "§4.3 E3",
+      "severity": "blocker",
+      "baseline": {
+        "kn10_rows": 0,
+        "kn10_a_rows": 16787,
+        "kn10_b_rows": 12407
+      },
+      "baseline_note": "kn10_A/kn10_B 行数取自 csv album 统计,旧表同源",
+      "target_v1": {
+        "kn10_rows": ">6000"
+      },
+      "target_final": {
+        "kn10_rows": ">6000"
+      },
+      "root_cause": "therā/therī(book 143/144)被赋 kn10_A/kn10_B 且归属互相矛盾;wbw 中 paraN_kn10 标记 6533 行在 related 中映射丢失",
+      "fix_stage": "batch1 书级配置表"
+    },
+    {
+      "id": "E4_empty_book_name",
+      "title": "空 book_name(无注释体系书)",
+      "doc_ref": "§4.3 E4",
+      "severity": "expected",
+      "baseline": {
+        "rows": 112965
+      },
+      "target_v1": {
+        "rows": "~112965"
+      },
+      "target_final": {
+        "rows": "~112965"
+      },
+      "root_cause": "nīti/语法/词典类书无 cs 标记体系,不参与注释关系",
+      "fix_stage": "不修,维持现状(§6.7)"
+    },
+    {
+      "id": "E5_book_id_zero",
+      "title": "book_id 未赋值",
+      "doc_ref": "§4.3 E5",
+      "severity": "minor",
+      "baseline": {
+        "rows": 354,
+        "books": 201
+      },
+      "target_v1": {
+        "rows": "<=354"
+      },
+      "target_final": {
+        "rows": "<=354"
+      },
+      "root_cause": "各文件 para 1-2 书前页,语义正确;另 sn 280/281 整段归错前册",
+      "fix_stage": "batch1 book_id 层按 book_titles 重跑"
+    },
+    {
+      "id": "E6_coverage_gap",
+      "title": "覆盖缺口(wbw 有段落但 related 无行)",
+      "doc_ref": "§4.3 E6",
+      "severity": "major",
+      "baseline": {
+        "segments": 3466
+      },
+      "target_v1": {
+        "segments": "<500"
+      },
+      "target_final": {
+        "segments": "<100"
+      },
+      "root_cause": "主体为缩写区间丢失(E7),其余为 wbw_templates 整段缺失",
+      "fix_stage": "batch1 + batch4"
+    },
+    {
+      "id": "E7_abbrev_interval_lost",
+      "title": "缩写区间丢失(para292-3 型)",
+      "doc_ref": "§4.3 E7",
+      "severity": "blocker",
+      "baseline": {
+        "marker_segments": 1517,
+        "books": 44,
+        "segments_without_rows": 1292,
+        "segments_with_garbage": 225
+      },
+      "target_v1": {
+        "segments_without_rows": 0,
+        "segments_with_garbage": 0
+      },
+      "target_final": {
+        "segments_without_rows": 0,
+        "segments_with_garbage": 0
+      },
+      "root_cause": "VRI 缩写语法 para292-3(=292-293)旧生成器不识别:多数跳过,少数误解析为废值",
+      "fix_stage": "batch1 导出器缩写补齐规则"
+    },
+    {
+      "id": "E8_flat_pollution",
+      "title": "书边界污染平铺",
+      "doc_ref": "§4.3 E8",
+      "severity": "blocker",
+      "baseline": {
+        "groups": 1,
+        "rows": 1499
+      },
+      "baseline_note": "实测复核后收窄了判据:污染的准确签名是「整段零 cs 标记却被写进非零 cs」。按此判全库只有 book 207 / book_id 259 kaṅkhāvitaraṇī 一段(1499 行恒 cs=75)。文档 §4.3 原列的另外几组里,book 212/273(669 行)、book 180/213、book 209/261 都是 cs 恒 0,0 是「未赋值」不是编造值,不算污染;book 152/46/116/154/204 则是章回绕(E2)被误判——book 152 有 516 个标记却只 24 个 cs 值,正是 22 次回绕造成的。",
+      "target_v1": {
+        "groups": 0
+      },
+      "target_final": {
+        "groups": 0
+      },
+      "root_cause": "换书(book_id 切换)后无标记,旧生成器无限沿用上一个 cs 值",
+      "fix_stage": "batch1 留空 + batch4 LLM"
+    },
+    {
+      "id": "E9_no_marker_books",
+      "title": "全书无标记(related 有行但 wbw 零标记)",
+      "doc_ref": "§4.3 E9",
+      "severity": "major",
+      "baseline": {
+        "books": 16,
+        "book_list": [
+          8,
+          15,
+          16,
+          25,
+          37,
+          39,
+          40,
+          41,
+          42,
+          44,
+          45,
+          47,
+          48,
+          56,
+          61,
+          129
+        ]
+      },
+      "target_v1": {
+        "books": 16,
+        "note": "v1 只按 wbw 重放,这些书自然无行"
+      },
+      "target_final": {
+        "books": 15,
+        "note": "book 129 用 csv 回填(csv 有 6580 非零行),其余 15 本 csv 也是全零,源头没有"
+      },
+      "root_cause": "VRI 源文件无锚点",
+      "fix_stage": "batch4:129 用 csv,其余维持现状",
+      "baseline_note": ""
+    },
+    {
+      "id": "E10_selfmade_names",
+      "title": "自造名体系(NK / subo / dict)",
+      "doc_ref": "§4.3 E10",
+      "severity": "expected",
+      "baseline": {
+        "nk_rows": 985,
+        "subo_rows": 4256,
+        "dict_rows": 6646
+      },
+      "baseline_note": "行数为 csv album 口径的近似值,check.php 会实测回填",
+      "target_v1": {
+        "note": "保留不动,架构正确"
+      },
+      "target_final": {
+        "note": "保留不动"
+      },
+      "root_cause": "非 SC 体系书对的自造 album 名,与 dn1/dn1_A 同构",
+      "fix_stage": "不改名,仅修其中的乱码/缩写(§6.7)"
+    },
+    {
+      "id": "D_continuity",
+      "title": "同 (book, book_name, cs_para) 的 para 不连续",
+      "doc_ref": "§4.2 正确性判据",
+      "severity": "watch",
+      "baseline": {
+        "broken_groups": 9026,
+        "books": 69,
+        "extra_segments": 30204
+      },
+      "target_v1": {
+        "broken_groups": "decrease"
+      },
+      "target_final": {
+        "broken_groups": "decrease"
+      },
+      "root_cause": "部分为合法的回指补充(cs 小幅回退),部分为章回绕与污染导致的真错",
+      "fix_stage": "观察项,不做硬断言;batch3 后应显著下降"
+    },
+    {
+      "id": "D_mirror_alignment",
+      "title": "镜像型书对两侧 max(cs_para) 一致",
+      "doc_ref": "§4.2 / §8",
+      "severity": "blocker",
+      "baseline": {
+        "aligned": {
+          "dn1": 559,
+          "kn6": 1289,
+          "kn9": 524,
+          "abhi5": 918
+        },
+        "misaligned": [
+          "abhi3",
+          "abhi4",
+          "abhi6",
+          "abhi7"
+        ]
+      },
+      "target_v1": {
+        "note": "aligned 四组必须保持相等;misaligned 四组 batch3 处理"
+      },
+      "target_final": {
+        "note": "全部对齐"
+      },
+      "root_cause": "义注/复注段的标记即被注书段落号;abhidhamma 系自有编号导致跨侧错位",
+      "fix_stage": "batch1 出口断言 + batch3 补丁后缀"
+    },
+    {
+      "id": "D_interval_expansion",
+      "title": "区间标记展开行数 == M − N + 1",
+      "doc_ref": "§6.3 验收断言",
+      "severity": "blocker",
+      "baseline": {
+        "note": "旧表未做此断言,check.php 首跑回填实测值"
+      },
+      "target_v1": {
+        "mismatched_markers": 0
+      },
+      "target_final": {
+        "mismatched_markers": 0
+      },
+      "root_cause": "旧生成器对 151-152 型一对多展开不完整",
+      "fix_stage": "batch1"
+    },
+    {
+      "id": "D_book_regression",
+      "title": "基线合格书回归",
+      "doc_ref": "§5 汇总",
+      "severity": "blocker",
+      "baseline": {
+        "note": "首跑生成 baseline.json,冻结旧表中零错误信号的书"
+      },
+      "target_v1": {
+        "regressed_books": 0
+      },
+      "target_final": {
+        "regressed_books": 0
+      },
+      "root_cause": "重建可能破坏本来正确的书",
+      "fix_stage": "每轮必检"
+    },
+    {
+      "id": "D_pairing",
+      "title": "配对质量(可信配对段数 / 膨胀键)",
+      "doc_ref": "§3 查询逻辑 / §6.1 回绕处理",
+      "severity": "blocker",
+      "baseline": {
+        "rows_paired_trusted": 177016,
+        "keys_bloated": 6671,
+        "keys_bloated_bad": 1413
+      },
+      "target_v1": {
+        "rows_paired_trusted": ">=177016"
+      },
+      "target_final": {
+        "rows_paired_trusted": "尽量大",
+        "keys_bloated_bad": "尽量小"
+      },
+      "root_cause": "章回绕让同一个 (book_name, cs_para) 在几十个章里重复,index() 一次查询捞回上千段",
+      "note": "可信配对 = key 跨文件命中、且在任何单本书里都不超过 10 段。直接数 rows_paired 会把回绕噪声算成资产——kn10 加后缀后 rows_paired 从 23757 掉到 6279 看着像灾难,其实掉的几乎全是 book 144章 43-56 的虚假配对(那几章本来就没有义注,是靠撞在一起的 kn10:1 假装配上的)。",
+      "fix_stage": "batch3 章后缀 + batch4 补丁"
+    }
+  ],
+  "rounds": [
+    {
+      "round": 1,
+      "date": "2026-09-09",
+      "table": "related_paragraphs_v1",
+      "rows": 638076,
+      "scripts": "build_markers.php → build_book_config.php → export.php → check.php → diff.php",
+      "result": {
+        "E1_cs_garbage": "1242 → 0",
+        "E3_kn10_missing": "0 → 25506(kn10_A/kn10_B 清零)",
+        "E6_coverage_gap": "3464 → 1(仅 book 11 para 1577 的截断标记)",
+        "E7_abbrev_interval_lost": "1292 段无行 + 225 段废值 → 0 + 0",
+        "E8_flat_pollution": "1499 行 → 0",
+        "D_interval_expansion": "1611 个区间标记展开不符 → 0",
+        "D_mirror_alignment": "四组镜像判据保持(dn1 559 / kn6 1289 / kn9 524 / abhi5 918)",
+        "clean_books": "128 → 148",
+        "E2_chapter_wrap": "429 → 677(未处理,留给章后缀批次;旧表的乱码与污染此前掩盖了部分真回绕)"
+      },
+      "diff_vs_old": {
+        "same": "480290 段 / 91.8%",
+        "only_in_old": "1 段(截断标记)",
+        "only_in_new": "3466 段(区间展开补回,与旧表的覆盖缺口数一致)",
+        "cs_changed": "10371 段 —— 8600 段新归零(防污染/防越界沿用)、528 段新赋值、1290 段两侧都非零而边界不同",
+        "name_changed": "29156 段 —— 29146 段是 kn10 家族修复(books 143/144/107),其余 10 段是各文件 book_tag 所在段本身"
+      },
+      "open": [
+        "book 129(6605 段)现为 cs=0 占位,待用 cs6_para.csv 回填(csv 有 6580 非零行)",
+        "20 段 segment_without_markers 已输出 cs=0 占位,待 LLM 归属",
+        "book 11 para 1577 的 para179- 截断标记待人工定",
+        "E2 章回绕 677 处未处理",
+        "1290 段两侧都非零而边界不同,需抽样复核(book 110 已查:旧表把 cs=5 边界提前 7 段,wbw 无依据,新值站得住)"
+      ]
+    },
+    {
+      "round": 2,
+      "date": "2026-09-09",
+      "table": "related_paragraphs_v2",
+      "scripts": "align_chapters.php → apply_chapters.php",
+      "approach": "跨侧章对齐:以 mūla 侧的 cs 重置段为章号定义,注释侧用带空位的序列比对(Needleman–Wunsch,打分基于两侧每章 max(cs) 的接近程度)对齐过去,两侧用同一套章号加后缀。每个 book_name 改名前后实测一次可信配对段数,掉了就整名回滚——指标把关,不是规则把关。",
+      "result": {
+        "E2_chapter_wrap": "399 → 116(旧表 395)",
+        "D_pairing.rows_paired_trusted": "186744 → 232557(旧表 177016,+31%)",
+        "D_pairing.keys_cross_book": "29005 → 34878",
+        "D_pairing.keys_bloated_bad": "1259 → 958(旧表 1413)",
+        "D_mirror_alignment": "0 偏离,保持",
+        "clean_books": "156 → 189(旧表 130)",
+        "applied": "17 个 book_name,改名 165779 行,无一回归"
+      },
+      "open": [
+        "5 个名字加后缀后可信配对归零或下跌,已自动回滚:vin8、dict、abhi8、vin7(并列的两本书被当成顺序拼接)、abhi7(3429→2940)",
+        "20 个名字跨侧对齐置信不足未处理:abhi2 abhi9 an11 an4 an5 an7 an9 kn2 kn3 kn6 kn7 mn1 mn1_A sn1 sn5 vin1 vin2 vin3 vin4 vin5——它们的共同特征是 mūla 侧 cs 单调无回绕、回绕只在注释侧,两侧用的不是同一套编号,序列比对无从下手",
+        "剩余 116 处回绕分布在 27 本",
+        "章标题不能当通用对齐信号:book 143(1. Buddhavaggo…)与 book 107(Dīpaṅkaro buddho…)标题完全对不上,文档 §6.4 的三层同名标题只适用于 vinaya 那组"
+      ]
+    }
+  ]
+}

+ 116 - 0
api-v13/scripts/related/lib/Logger.php

@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * 重建工程专用日志器。
+ *
+ * 迭代流程是「脚本跑 → 日志和报告交给 LLM 评估 → 改规则 → 再跑」,所以日志的读者
+ * 是模型不是人:宁可啰嗦,但必须结构化。unresolved() 记录的是脚本自己判定
+ * 「我处理不了」的点,它们是下一轮规则迭代的输入,单独成文件。
+ */
+class RpLogger
+{
+    private $handle;
+
+    private array $counters = [];
+
+    /** @var array<int, array<string, mixed>> */
+    private array $unresolved = [];
+
+    private float $startedAt;
+
+    public function __construct(
+        private string $name,
+        private string $reportDir,
+        private bool $echoToStdout = true,
+    ) {
+        $this->startedAt = microtime(true);
+        $this->handle = fopen($this->reportDir."/{$name}.log", 'w');
+        $this->line('INFO', "==== $name 开始 ".date('Y-m-d H:i:s').' ====');
+    }
+
+    public function info(string $message): void
+    {
+        $this->line('INFO', $message);
+    }
+
+    public function warn(string $message): void
+    {
+        $this->line('WARN', $message);
+    }
+
+    public function error(string $message): void
+    {
+        $this->line('ERROR', $message);
+    }
+
+    /** 计数器:高频事件不逐条打印,只累计,收尾时汇总。 */
+    public function count(string $key, int $n = 1): void
+    {
+        $this->counters[$key] = ($this->counters[$key] ?? 0) + $n;
+    }
+
+    public function counters(): array
+    {
+        return $this->counters;
+    }
+
+    /**
+     * 脚本无法判定的点。type 是规则名,供下一轮按类型聚合决定要不要加规则。
+     */
+    public function unresolved(string $type, array $context): void
+    {
+        $this->unresolved[] = ['type' => $type] + $context;
+        $this->count("unresolved.$type");
+    }
+
+    /** 收尾:写计数汇总与 unresolved 清单,返回汇总数组。 */
+    public function finish(): array
+    {
+        $elapsed = round(microtime(true) - $this->startedAt, 1);
+        ksort($this->counters);
+
+        $this->line('INFO', '---- 计数汇总 ----');
+        foreach ($this->counters as $key => $value) {
+            $this->line('INFO', sprintf('  %-46s %10d', $key, $value));
+        }
+
+        $byType = [];
+        foreach ($this->unresolved as $item) {
+            $byType[$item['type']] = ($byType[$item['type']] ?? 0) + 1;
+        }
+        if ($byType !== []) {
+            $this->line('WARN', '---- 未决问题(按类型) ----');
+            foreach ($byType as $type => $n) {
+                $this->line('WARN', sprintf('  %-46s %10d', $type, $n));
+            }
+        }
+
+        $path = $this->reportDir."/{$this->name}.unresolved.json";
+        rp_json_write($path, [
+            'generated_at' => date('c'),
+            'total' => count($this->unresolved),
+            'by_type' => $byType,
+            'items' => $this->unresolved,
+        ]);
+
+        $this->line('INFO', "未决清单:$path");
+        $this->line('INFO', "==== {$this->name} 结束,耗时 {$elapsed}s ====");
+        fclose($this->handle);
+
+        return [
+            'counters' => $this->counters,
+            'unresolved_total' => count($this->unresolved),
+            'unresolved_by_type' => $byType,
+            'elapsed_seconds' => $elapsed,
+        ];
+    }
+
+    private function line(string $level, string $message): void
+    {
+        $row = sprintf('[%s] %-5s %s', date('H:i:s'), $level, $message);
+        fwrite($this->handle, $row."\n");
+        if ($this->echoToStdout) {
+            fwrite(STDOUT, $row."\n");
+        }
+    }
+}

+ 202 - 0
api-v13/scripts/related/lib/MarkerParser.php

@@ -0,0 +1,202 @@
+<?php
+
+/**
+ * wbw_templates 里 .ctl. 锚点标记的解析器。
+ *
+ * 这些标记来自 VRI html 的 <a name="..."> 锚点,是整个 related_paragraphs 的唯一
+ * 事实来源。旧生成器(cs6_para.csv 那条链路)在这里翻过车——缩写区间被跳过或
+ * 误解析成六位数废值——所以解析规则集中在这一个类里,导出器和检测器共用同一份,
+ * 不允许各写一遍。
+ *
+ * 形态实测(type='.ctl.' and style='#a#',330267 行):
+ *   pagemark 167647 / paraN 116921 / paraN_book 39998 / paraN-M 3611
+ *   / 书名·章标记 1096 / paraN-M_book 989 / 链式 4 / 截断 1
+ */
+class MarkerParser
+{
+    /** 解析结果超过此值一律视为废值,拒绝输出。实测合法上界 3183。 */
+    public const CS_MAX = 5000;
+
+    public const KIND_SINGLE = 'single';          // para4
+
+    public const KIND_INTERVAL = 'interval';      // para151-152 / para292-3 / para292-3-6
+
+    public const KIND_BOOK_TAG = 'book_tag';      // dn1
+
+    public const KIND_CHAPTER = 'chapter';        // dn1_9 / an5_1_1 —— 章标记或义注标记,同形歧义
+
+    public const KIND_PAGE = 'page';              // P1.0023
+
+    public const KIND_TRUNCATED = 'truncated';    // para179-
+
+    public const KIND_UNKNOWN = 'unknown';
+
+    /**
+     * @return array{
+     *   kind: string,
+     *   cs: list<int>,          解析出的 cs 值(已展开区间)
+     *   book_name: ?string,     标记自带的书名后缀
+     *   number: ?int,           chapter 形态的首级编号
+     *   numbers: ?list<int>,    chapter 形态的完整编号路径(an5_1_1 → [1,1])
+     *   repaired: ?string,      规则修补过的标记,须记 issue 复核
+     *   raw: string,
+     *   error: ?string,         非空表示拒绝输出,调用方须记 issue
+     * }
+     */
+    public static function parse(string $word): array
+    {
+        $base = [
+            'kind' => self::KIND_UNKNOWN,
+            'cs' => [],
+            'book_name' => null,
+            'number' => null,
+            'numbers' => null,
+            'repaired' => null,
+            'raw' => $word,
+            'error' => null,
+        ];
+
+        // 页码/卷标 P/M/V/T/O × 0-5:本轮一律忽略(§6.7)
+        if (preg_match('/^[A-Z][0-9]/', $word)) {
+            return ['kind' => self::KIND_PAGE] + $base;
+        }
+
+        if (! str_starts_with($word, 'para')) {
+            // 纯书名 dn1(书上下文事件)或 dn1_9(章标记 / 义注标记)
+            // 章标记,可带多级编号路径:dn1_9 是一级,an5_1_1 是两级(实测 13 本 247 行,
+            // 义注书 100-102 与 mūla 书 82-92 共用同一套编号,是跨文件章界对齐的抓手)。
+            if (preg_match('/^([a-z][a-z0-9]*)((?:_[0-9]+)+)$/', $word, $m)) {
+                $numbers = array_values(array_map('intval', array_filter(explode('_', $m[2]), 'strlen')));
+
+                return [
+                    'kind' => self::KIND_CHAPTER,
+                    'book_name' => $m[1],
+                    'number' => $numbers[0],
+                    'numbers' => $numbers,
+                ] + $base;
+            }
+            if (preg_match('/^[a-z][a-z0-9]*$/', $word)) {
+                return ['kind' => self::KIND_BOOK_TAG, 'book_name' => $word] + $base;
+            }
+
+            return $base;
+        }
+
+        $body = substr($word, 4);
+
+        // 尾部 _book 后缀。区间与单值都可能带,如 para1008-9_sn5(实测 989 行)。
+        $bookName = null;
+        if (preg_match('/^(.*?)_([a-z][a-z0-9_]*)$/', $body, $m)) {
+            $body = $m[1];
+            $bookName = $m[2];
+        }
+
+        if ($body === '' || ! preg_match('/^[0-9]/', $body)) {
+            return ['error' => '标记主体不是数字'] + $base;
+        }
+
+        // para179- :区间右端缺失,全库仅 book 11 para 1577 一处,留给人工。
+        if (str_ends_with($body, '-')) {
+            return ['kind' => self::KIND_TRUNCATED, 'book_name' => $bookName, 'error' => '区间右端缺失'] + $base;
+        }
+
+        $parts = explode('-', $body);
+        foreach ($parts as $part) {
+            if (! preg_match('/^[0-9]+$/', $part)) {
+                return ['error' => "区间片段非数字:$part"] + $base;
+            }
+        }
+
+        if (count($parts) === 1) {
+            $cs = (int) $parts[0];
+            if ($cs > self::CS_MAX) {
+                return ['book_name' => $bookName, 'error' => "cs 超值域:$cs"] + $base;
+            }
+
+            return ['kind' => self::KIND_SINGLE, 'cs' => [$cs], 'book_name' => $bookName] + $base;
+        }
+
+        // 链式 para292-3-6:逐段以前一个完整值补齐,取首尾展开(实测仅 4 行)。
+        $start = (int) $parts[0];
+        $current = $start;
+        for ($i = 1; $i < count($parts); $i++) {
+            $current = self::completePrefix($current, $parts[$i]);
+            if ($current === null) {
+                return ['book_name' => $bookName, 'error' => "区间右端无法补齐:$body"] + $base;
+            }
+        }
+        $end = $current;
+
+        $repaired = null;
+        if ($end < $start) {
+            // 倒序区间是 VRI 源里的高位笔误,低位是对的:实测 para504-407 前邻 502-503
+            // 后邻 508(真值 504-507)、para706-608 前邻 703-705 后邻 709(真值 706-708)。
+            // 丢掉右端高位、只用低位重新补齐即可还原。全库仅 3 行,一律记 issue 人工复核。
+            $tail = end($parts);
+            $end = self::repairReversedEnd($start, $tail);
+            if ($end === null) {
+                return ['book_name' => $bookName, 'error' => "区间倒序且无法修补:$body"] + $base;
+            }
+            $repaired = "倒序区间按低位补齐:$body → $start-$end";
+        }
+        if ($end > self::CS_MAX || $start > self::CS_MAX) {
+            return ['book_name' => $bookName, 'error' => "cs 超值域:$start-$end"] + $base;
+        }
+        if ($end - $start > 2000) {
+            return ['book_name' => $bookName, 'error' => "区间过宽:$start-$end"] + $base;
+        }
+
+        return [
+            'kind' => self::KIND_INTERVAL,
+            'cs' => range($start, $end),
+            'book_name' => $bookName,
+            'repaired' => $repaired,
+        ] + $base;
+    }
+
+    /**
+     * VRI 缩写区间语法:右端只写变化的低位,用左端补齐前缀。
+     *   292-3   → 293      (补 "29")
+     *   1008-9  → 1009     (补 "100")
+     *   15-8    → 18       (补 "1")
+     *   298-3   → 303      (补出来 293 < 298,进位加 10^1)
+     * 右端位数不少于左端时不是缩写,原样返回。
+     */
+    public static function completePrefix(int $left, string $rightDigits): ?int
+    {
+        $leftDigits = (string) $left;
+        $rightLen = strlen($rightDigits);
+
+        if ($rightLen >= strlen($leftDigits)) {
+            return (int) $rightDigits;
+        }
+
+        $prefix = substr($leftDigits, 0, strlen($leftDigits) - $rightLen);
+        $completed = (int) ($prefix.$rightDigits);
+
+        if ($completed <= $left) {
+            // 低位回绕,向上进一位:298-3 的 3 指的是 303 不是 293。
+            $completed += 10 ** $rightLen;
+        }
+
+        return $completed > $left ? $completed : null;
+    }
+
+    /**
+     * 倒序区间的还原:逐步丢弃右端高位,只保留低位再按前缀补齐,取第一个大于左端
+     * 且区间宽度合理的结果。
+     *   504-407 → 低两位 "07" 补成 507
+     *   706-608 → 低两位 "08" 补成 708
+     */
+    public static function repairReversedEnd(int $start, string $rightDigits): ?int
+    {
+        for ($keep = strlen($rightDigits) - 1; $keep >= 1; $keep--) {
+            $candidate = self::completePrefix($start, substr($rightDigits, -$keep));
+            if ($candidate !== null && $candidate > $start && $candidate - $start <= 20) {
+                return $candidate;
+            }
+        }
+
+        return null;
+    }
+}

+ 85 - 0
api-v13/scripts/related/lib/boot.php

@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * related_paragraphs 重建工程的公共引导。
+ *
+ * 这些脚本刻意留在 scripts/ 而不是 app/Console/Commands/:重建期间它们会被反复
+ * 改写、丢弃、重跑,不属于应用的常驻命令面。导出器稳定后再收编成 artisan command。
+ */
+
+use Illuminate\Contracts\Console\Kernel;
+
+require __DIR__.'/../../../vendor/autoload.php';
+
+$app = require __DIR__.'/../../../bootstrap/app.php';
+$app->make(Kernel::class)->bootstrap();
+
+require __DIR__.'/Logger.php';
+
+/** 本工程所有产物的落地目录。 */
+function rp_report_dir(): string
+{
+    $dir = __DIR__.'/../report';
+    if (! is_dir($dir)) {
+        mkdir($dir, 0o755, true);
+    }
+
+    return $dir;
+}
+
+function rp_data_dir(): string
+{
+    return __DIR__.'/../data';
+}
+
+/** 命令行参数:--key=value / --flag,返回 [$options, $positional]。 */
+function rp_args(array $argv): array
+{
+    $options = [];
+    $positional = [];
+    foreach (array_slice($argv, 1) as $arg) {
+        if (str_starts_with($arg, '--')) {
+            $body = substr($arg, 2);
+            if (str_contains($body, '=')) {
+                [$k, $v] = explode('=', $body, 2);
+                $options[$k] = $v;
+            } else {
+                $options[$body] = true;
+            }
+        } else {
+            $positional[] = $arg;
+        }
+    }
+
+    return [$options, $positional];
+}
+
+/**
+ * 表名白名单校验。这些脚本会把表名拼进 SQL(标识符不能用绑定参数),
+ * 所以只允许我们自己的表族,避免手滑打错表名时打到生产数据。
+ */
+function rp_assert_table(string $table): string
+{
+    if (! preg_match('/^related_paragraphs(_[a-z0-9_]+)?$/', $table)) {
+        throw new InvalidArgumentException("拒绝操作非 related_paragraphs 表族的表:$table");
+    }
+
+    return $table;
+}
+
+function rp_json_write(string $path, mixed $data): void
+{
+    file_put_contents(
+        $path,
+        json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)."\n"
+    );
+}
+
+function rp_json_read(string $path): mixed
+{
+    if (! file_exists($path)) {
+        throw new RuntimeException("找不到文件:$path");
+    }
+
+    return json_decode(file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
+}