Files
PolyGateway/research-wiki/reviews/2026-10-22-issue34-branch-review.md

8.1 KiB

type, node_id, title, date, severity
type node_id title date severity
review review:2026-10-22-issue34-branch-review #34 OCR 整份文档解析 合并前验收与审查报告 2026-10-22 approved

#34 OCR 整份文档解析 合并前验收与审查报告

  • 分支 fix/issue34-ocr-document,基线 25a90eb(1.3.10),Head cb1e08f(17 个提交,目标 1.3.11;本报告随后追加一个文档提交)。
  • 设计 designs/2026-10-21-issue34-ocr-document-design.md(已获人类批准:H1/H5/H6 批准,H2 授权另开 #35/#36,H3 待下游确认,H4 发布逐步等指令);计划 plans/2026-10-21-issue34-ocr-document.md。
  • 结论: 实现与验证完成,Critical 0、Important 已全部修复。发布(合并/tag/上传/Release/关 #34)未执行,等人类指令。

1. 需求覆盖(issue #34 → 实现)

issue 期望 实现 证据
上传按类型设 filename/Content-Type 库按内容判定(H5 有意替换「调用方声明」): 图片魔数优先 → 前 1KB 内 %PDF- → doc.pdf,其余沿用 image.jpg;三个方法共用 test_monkey_ocr.py::TestSniffMedia、TestUploadLabelPerMethod、TestParseDocument::test_upload_label_matrix_for_the_document_entry;活体 recognize_text(PDF) 返回真实文本而非幻觉串
逐块 类型/页码/bbox/文字,服务阅读序 OcrDocumentElement(继承 OcrLayoutElement + text);只读 _middle.json;表格为 HTML test_monkey_document.py(§5.1 契约逐行);4 份真实包离线冒烟 29/89/30/29 块全部与 middle/content_list(反转义)一致
整篇 Markdown OcrDocumentResult.markdown,按名精确配对 .md 同上;真实包 markdown == .md 原文
长文档超时与熔断确认 库内无延迟型判定(grep 已证);timeout_s 非总耗时上界,硬上限 = call_deadline_s ≤ lease_ttl_s;文档线独立 scope 配方 TestNoLatencyJudgement(含已有失败计数/半开探针两种前置状态)、持续慢速下载 → CallDeadlineExceeded、README「运维须知」
parse_layout 不动 签名/返回类型/错误文案不变;仅上传分支(H6)与共用第一段协议新增 download_url 校验 独立审查对 5501 个输入与 2486 个场景做基线差分,仅 %PDF- 字样载荷的上传标签有差异(已登记)

2. 本会话证据(命令 → 结果)

声明 命令 结果
全套通过 pytest tests/ -q --cov=src/polygateway(退出码取自文件,无管道) 退出 0;2239 passed, 23 skipped, 113 deselected(slow);总覆盖 96%
格式/lint/依赖契约 make ci 退出 0;108 files formatted、ruff All checks passed、Contracts: 1 kept, 0 broken
复杂度 radon cc <ocr.py, _monkey_document.py, monkey_ocr.py> -n C -s 无 C 及以上(仅 openai_compat.py::complete 为未触及的既有 C)
活体 pytest tests/integration/test_monkey_ocr_document_live.py -m slow 3 passed(8.85s);默认套件 3 deselected
真实多页 PDF 端到端 OcrClient.from_env("OCR_DOC") 调 rich.pdf(4 页)/tbl.pdf(2 页含表) 89/30 个元素,与直连存证一致;表格 HTML 取出;各 1 次尝试
红→绿 每任务 scratchpad/T*-red.log → T*-green.log T1–T6 红灯原因均为目标行为缺失(导入失败或 AttributeError: no attribute 'parse_document')
测试非空转 变异检查(还原/改坏实现 → 测试转红 → 恢复) 本会话十余类变异全部被抓到: 异常边界放错位置(47 个失败)、status==500/前缀判据、同步解析、体积检查先于错误状态、_summarize、早期装配校验、整包上限、aread/有界读取、reasoning_applies、探针归还、download_url 校验、isinstance 分派;独立审查另做 86 个变异、0 存活

3. 评审轮次与处置

轮次 审查者 结论 处置
设计论证 独立 Plan subagent(含本机 MonkeyOCR 源码核对) 弃「content_list 对位」改 middle-only 等 全部采纳(设计 §12)
设计审查 Codex(只读) 否→修订后进入;9 条全部成立 全部修订(设计「审查记录」)
计划审查 Codex(只读) 修订后进入执行;10 条全部成立,第 1 条为我方计划缺陷 全部修订(计划 §5)
合并前独立验证 全新上下文 verifier 无 Critical;Important 4 条 I-1 异常漏出、I-2 整包上限无测试、I-3 业务词汇、I-4 三处空转测试——全部修复并用变异证明
整分支 Codex 审查 Codex 未完成: 沙箱报 usage limit,只读了设计/计划/部分代码即终止,无任何分级结论 以全新上下文的独立 Claude 对抗式审查替代(见下行);Codex 额度恢复后可补跑,不影响本报告其余结论
对抗式代码审查 全新上下文 Claude(自写模糊/变异脚本,假服务压测) 建议合并;Critical 0,Important 3 见 §4

4. 对抗式审查发现与处置

# 发现 核验 处置
I-1 _summarize 由 hasattr 改 isinstance,鸭子类型 transport 结果以 AttributeError 漏出 本机复现(SimpleNamespace(text=...)) 改回结构分派(有 markdown → 文档;有 text → 文本;其余版面),加回归测试
I-2 文档路径的错误体 aread() 无上限(600 MiB 的 500 使 RSS 涨到 1.8 GiB) 属实(基线非流式 get 同样,但新代码声称有界) 错误体只读前 64 KiB 并复制成已缓冲响应;加测试证明只消费上限那么多
I-3 畸形 download_url(控制字符/坏方括号/越界端口)让 httpx.InvalidURL 漏出;探针不归还 本机复现;parse_layout 基线同样 在共用的 _post_parse 一处校验,归瞬时错误、不发第二段请求;parse_layout 顺带受益(CHANGELOG 登记);不限制主机(基线接受绝对地址)
M-1 嗅探副作用: 前 1KB 含 %PDF- 字样的非 PDF 文本被改标;BM 两字节魔数太弱 属实 BMP 加 DIB 头大小校验;CHANGELOG/README 登记副作用
M-2 字节上限≠内存上限(JSON 解析后可达 23 倍;成员条数无上限) 属实,仅服务异常时成立 README 改为诚实口径;不实现 EOCD 预读(真实样本约 72 KB/页)
M-3 to_thread 不是「立即生效」: GIL 下事件循环仍有停顿,取消后线程自然收尾 属实 文档改「基本不被占住」并给实测数
M-4 parse_layout 的 ZIP 路径仍会漏原生异常(基线即有) 属实,按设计保持原样 后续项(见 §6)
M-5/6/7 设计文档结局表与实现不一致;类 docstring 过时;测试注释含业务词汇 属实 全部修正
M-8 page_idx 必须等于页序,服务若跳页则整份失败 设计取舍 保留;列入未验证项

5. 没能验证的部分(如实登记)

  • 线上服务: 旋转页/带批注页/加密 PDF 的 doc.pdf vs image.jpg 差分;带密码 PDF 的服务端报错文案(若不在标记集合,走瞬时重试并计熔断);线上 backend 是否 sync-only(队头阻塞);真实 httpcore 逐次读超时行为(MockTransport 不执行它);need_drop 恒为 False 的线上证实。
  • 样本局限: 多行/多 span 文本块、inline_equation span、嵌套 caption/footnote 三条路径无真实样本,仅由构造 fixture 测试(已在 CHANGELOG/README 标注「未经实测」)。
  • 未执行: make wiki-check(需外部 Gitea Wiki 克隆路径,站点自 2026-08-02 下线);Redis 限流/熔断后端与 Postgres 遥测对新入口的组合(无对应环境新增用例,既有套件中的后端用例通过);整分支 Codex 审查(额度)。
  • 下游: H3(CHSAnalyzer3 是否把「服务不可用」一族按延期重投处理)未向下游证实。

6. 后续项与待人类指令

项 状态
#35 共享 _classify_status 对确定性坏输入 500 仍归瞬时 已开
#36 recognize_text 不校验 success 已开
parse_layout ZIP 路径的原生异常漏出(OverflowError/NotImplementedError/RuntimeError)与 download_url 主机限制 人类 2026-10-22 批准新开,已开 #37
发布: 合并 main → push → tag v1.3.11 → 构建 → 上传 registry → 验证已发布 → 建 Release/挂仓库 → 关闭 #34 人类 2026-10-22 下令发布,按 CLAUDE.md §4.4.1 逐步执行;CHANGELOG 定版日期 2026-10-22