fix(parse-book): 独立复核揪出的2个真bug——recluster跨书实例归属被覆写+迁移章号正则误抓数量词

Bug1(parse_ingest _absorb):归并时用输家书名无条件覆写每条实例的来源书名→'二级归并母卡'里跨书实例的真实来源被抹成输家书名;改为保留实例原有书名(ins.get('书') or book)。已跑的718归并中75条实例/31母卡受影响,可从回溯归并审计的被并卡全文还原(待remediate)。

Bug2(parse_upgrade INLINE_CHAP_RE):裸'N章'分支把'隔3章/花了3章篇幅'数量词误当章号、还标最高置信'内嵌',违背人工精确化(拍板#5);改为只认'第X章'/'Ch.X'(区间取首章'第489-490章'→489),裸写法一律落待LLM重抽。迁移仅dry-run未落库、无数据影响。11条边界用例亲测通过。

独立opus子代理对抗复核确认无阻断性问题:无物理删知识卡/无dry-run漏写/无额度绕过/软删可逆/连接三段/调用契约完好。
This commit is contained in:
zizi 2026-07-17 11:52:54 +08:00
parent 178603568e
commit 46704ee5da
2 changed files with 7 additions and 2 deletions

View File

@ -532,7 +532,9 @@ def _absorb(mother, loser, sim, why):
"""把输家并入母卡(内存态,写库延后到写段统一落):输家实例(带书名归属)追加进母卡实例数组 """把输家并入母卡(内存态,写库延后到写段统一落):输家实例(带书名归属)追加进母卡实例数组
+ 记「回溯归并审计」(相似度/判定依据/被归并卡全文——全文留痕保证归并可逆)。""" + 记「回溯归并审计」(相似度/判定依据/被归并卡全文——全文留痕保证归并可逆)。"""
book = (loser.get("出处") or {}).get("书名") or "" book = (loser.get("出处") or {}).get("书名") or ""
add = [dict(ins, 书=book) for ins in (loser.get("实例") or [])] # 跨书归属:每条实例标来源书 # 跨书归属:优先保留实例原有的书名——输家可能是"此前已跨书吸并过的母卡",其实例里混有别书来源,
# 绝不能用输家自己的书名无条件覆写(那会把二级归并的真实来源抹成输家书名);无原书名的才补输家书名。
add = [dict(ins, 书=ins.get("书") or book) for ins in (loser.get("实例") or [])]
mother["实例"] = (mother.get("实例") or []) + add mother["实例"] = (mother.get("实例") or []) + add
mother.setdefault("回溯归并审计", []).append( mother.setdefault("回溯归并审计", []).append(
{"相似度": round(float(sim), 4), "判定依据": why, "被归并卡": loser}) {"相似度": round(float(sim), 4), "判定依据": why, "被归并卡": loser})

View File

@ -322,7 +322,10 @@ def _entry_win(x):
# 章级排序不用运行时窗号,而用真实章号(设计稿 §6.1「真实章号索引」的落点)。 # 章级排序不用运行时窗号,而用真实章号(设计稿 §6.1「真实章号索引」的落点)。
# 内嵌真实章号抽取:正文/台阶里原样出现的「第X章 / X章 / Ch.X」——迁移与降级共用 # 内嵌真实章号抽取:正文/台阶里原样出现的「第X章 / X章 / Ch.X」——迁移与降级共用
INLINE_CHAP_RE = re.compile(r"第\s*(\d+)\s*章|(?:Ch|CH|ch)\.?\s*(\d+)|(?<![0-9])(\d+)\s*章") # 只认"第X章"/"Ch.X"两种明确章号写法。刻意不收裸"N章"——它无法与"隔3章/花了3章篇幅"这类
# 数量词区分,误当章号会污染迁移(且被标成最高置信"内嵌"),违背人工精确化;裸写法一律落到待LLM重抽。
# 带"第"前缀时取首个数字,天然处理"第489-490章"→489(区间取首章、不取末章)。
INLINE_CHAP_RE = re.compile(r"第\s*(\d+)(?:\s*[-—~到]\s*\d+)?\s*章|(?:Ch|CH|ch)\.?\s*(\d+)")
def _extract_inline_chapter(text): def _extract_inline_chapter(text):