Repository navigation
fix(docs): inspect_pdf 单页读不出文字时不再整份失败 - #7890
Conversation
pdf.js 5.7.284 (and 6.4.299) throws "Cannot read properties of null (reading 'name')" from getTextContent when a content stream shows text at font size 0 before any font is set, the shape of invisible Aspose watermarks. inspectPdfPages read text outside any try/catch, so one such page failed the whole inspection with INSPECT_FAILED, and the hint told the model the generated file was broken and must be redone, even though the file renders fine elsewhere. Read page text inside its own try/catch, like the operator list: the page reports textError, visibilityUnverified=true and blank=false, and the other pages are inspected normally. A document pdf.js cannot open still fails as before. The process boundary accepts an optional string textError, inspect_pdf names those pages in its warning, and the INSPECT_FAILED hint no longer asserts that generation failed. Signed-off-by: Zhao Dengfeng <2370187+zhaodengfeng@users.noreply.github.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
[Medium impact] 本次改动看起来可以合并,未发现需要阻止合并的问题。
|
|
@codex review Please retry the review of current head Related upstream update: mozilla/pdf.js#22384 has now merged the fix for the zero-initial-font-size extraction error reported in mozilla/pdf.js#22381. This PR still provides per-page error isolation for extraction failures; the upstream merge alone does not establish that downstream installations have received a release containing that fix. |
|
Codex Review: Something went wrong. Try again later by commenting “@codex review”. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
MagicLizi
left a comment
There was a problem hiding this comment.
PR #7890 独立代码审查报告(auto · standard 档)
PR: #7890
head: ebb99c6426d2a662c1d3f1ff73d6b46b8a15427b(单 commit,同时是初始实现)
base: d9c8e0657772cd2fd9f3f631b84058e252d48702(main)
diffHash: d6fb527c6a855e4c25ecd9dfcb69fbb38c08726d68a6fb0c12a130f88d397002
Findings
没有 P0/P1。
以下仅记录、不阻断(P2 级,按规则不作为问题发出):
inspect_pdfwarning 文案中「结构算子解析未完成」会连带覆盖仅文字提取失败的页(算子其实解析成功),同句后半用「其中第 X 页是解析器读不出文字」作了澄清,语义无误导性结论。reviewPdfProcess.test.ts原有透传用例的 fixture 由「空白页」改成「textError 页」,blank:true字段的透传覆盖略有减少;校验是逐字段统一的,影响可忽略。
Rule coverage
按 references/rule-map.md 命中并读取的规则与逐项结论:
AGENTS.md(仓库边界、安全底线、Git 交付):改动限于apps/desktop/src/main/reviewer/**与packages/lizi-mcps/**,无越界;未触碰凭证/用户数据;commit 带 DCOSigned-off-by且与 author 一致。docs/dev-rules/development-workflow.md(P0/P1/P2 口径):按其口径判级,无 P0/P1;PR 模板三段齐全(format 门由 context 判定通过)。docs/dev-rules/electron-security-and-process-boundaries.md§8 清单:1–6 不适用(未改 Renderer/preload/IPC/CSP/导航,未新增特权能力);7 无新增安全边界;8 不适用(无辅助窗口)。解析不可信 PDF 仍留在既有一次性 utility process(128MB 堆上限、超时 kill)内,未放宽任何边界。docs/dev-rules/engineering-conventions.md清单:无裸 console;未改 IPC handler;main 侧新逻辑(逐页 try/catch)带主路径 + 错误路径单测(真实 pdf.js 复现用例);测试不涉外网/固定端口/真实子进程新增;无跨平台敏感路径改动;文案是 MCP 工具的模型侧输出(inspect_pdfDESCRIPTION/warning),沿用该文件既有中文直写约定,非桌面 UI 文案,不适用t()/i18n 流程;新增逻辑带职责注释。docs/dev-rules/architecture-invariants.md清单:1–4 不适用(无 package 依赖方向、动态 import、布局树改动)。docs/dev-rules/desktop-development.md(验证分层):改 TypeScript 已跑相关定向测试 + 两个受影响 package 的 typecheck,见 Verification。docs/dev-rules/protocol-compatibility.md:不适用——reviewPdfProcessProtocol.ts是同一二进制内 main↔utilityProcess 的进程内协议,非跨端 wire protocol;textError为新增可选字段,读侧(isReviewPdfPageInspection)防御式校验(undefined | string),新旧组合均兼容,无 IPC channel/allowlist 变化。- 安全与隐私(SKILL 3.2):context 扫描
hardHits=0, softHits=0, scanned=true;审查中未发现凭证/隐私/新依赖/数据外发;textError取解析器异常 message 截断 300 字符后仅进入本工具 JSON 输出,无落盘、无外发。
固定问题(rule-map):① 单一目的,描述/diff/测试/风险一致 ✓;② 共享符号读方均核对:ReviewPdfPageInspection 三处消费(子进程结果校验 reviewPdfProcess.ts:221、宿主透传 doc-tools/pdfInspector.ts、inspect_pdf.ts 的 decorated 展开保留 textError)均正确处理新字段,pageVisibilityUnverified 新参默认值保持旧行为,唯一调用方已更新 ✓;③ 无权限/凭证/远程边界改动 ✓;④ 未放松安全边界、无新增依赖 ✓;⑤ main 侧逻辑有真实 pdf.js 单测证据 ✓;⑥⑦⑧ 不适用 ✓。
Verification
全部在审查 worktree 内实际执行,命令自身退出码如实记录:
pnpm install --frozen-lockfile --prefer-offline EXIT=0
pnpm --dir apps/desktop exec vitest run src/main/reviewer/__tests__/pdfInspect.test.ts \
src/main/reviewer/__tests__/reviewPdfProcess.test.ts \
src/main/reviewer/__tests__/reviewPdfProcessPackaging.test.ts EXIT=0(3 files, 20 passed)
pnpm --dir packages/lizi-mcps exec vitest run src/__tests__/cindyDocsMcpServer.test.ts
EXIT=0(1 file, 114 passed)
pnpm --dir packages/lizi-mcps exec tsc --noEmit -p . EXIT=0
pnpm --filter desktop run typecheck EXIT=0
与 PR 描述声称的验证一致且全部复核通过。未执行:security-scan.mjs(standard 档不跑 heavy 专项,security 门 context 扫描已通过);实机双平台(macOS/Windows)差异不涉及(无路径/子进程行为改动)。PR 描述中作者未跑全量 apps/desktop typecheck 的说明已由本次补跑覆盖(本 worktree 依赖齐全,typecheck 通过)。
Intent alignment
- 描述来源:PR 标题与 body(2026-10-29T20:13Z 读取),「明确不包含」段与范围声明清晰;无关联 issue。
- 初始实现 SHA/范围:
ebb99c6426d2a662c1d3f1ff73d6b46b8a15427b单 commit(history.commits全量仅此一条),初始实现 = 待合并 head,累计 diff 即该 commit 的完整 diff,已逐行读取。 - 待合并 head:
ebb99c6426,与初始实现同一 revision,期间无多轮修复改写。 - Codex/Greptile 意见核对:Codex 两轮均执行失败("couldn't complete / unknown error"),未产出 findings 或 thread;Greptile 结论「未发现需要阻止合并的问题」;无已 Resolve thread、无维护者讨论 issue(
signoff.triggers为空)。作者留言说明上游 pdf.js#22384 已合并修复,但本 PR 的逐页错误隔离目标不变,与 body 一致。 - 对照结论(表格):
| 原目标/初始行为 | 最终行为与影响 | 代码/提交证据 | 变化依据 |
|---|---|---|---|
单页 getTextContent 抛错不再拖垮整份 inspect_pdf |
逐页 try/catch,出错页记 textError+visibilityUnverified、blank:false,其余页照常;整份打不开仍失败 |
reviewPdfUtilityProcess.ts:258-307 |
与 PR body 承诺一致 |
结果校验允许可选 textError 穿过进程边界 |
isReviewPdfPageInspection 新增 undefined | string 校验,透传至 MCP |
reviewPdfProcess.ts:221、pdfInspector.ts |
同上 |
inspect_pdf 指明受影响页码并修正误导性失败提示 |
warning 列出 textError 页码;INSPECT_FAILED 提示不再断言生成环节出错 |
inspect_pdf.ts:224-270,296-299 |
同上 |
Reviewer extract 作业保持原样 |
未改动(reviewPdfUtilityProcess.ts:79-137) |
同左 | body「明确不包含」声明,失败语义不同,属作者划定的合理边界 |
结论:一致。核心目标(逐页容错 + 误导提示修正)在最终 diff 中完整落实,无删除/削弱/无关扩范围,无待裁定方向问题。
Overall
pass —— 没有 P0/P1。原意一致性复核通过,可以进入 guarded Approve 与合并。
这次改了什么
摘要
inspect_pdf遇到 pdf.js 读不出文字的单页时,整次检查失败(INSPECT_FAILED),提示还断言“生成环节就出了问题,请重做”。但这类文件本身完好,MuPDF 等渲染器都能正常显示。根因在 pdf.js:内容流里还没设过字体时,如果第一次显示文字前设的字号是 0(
BT /F0 0 Tf (…) Tj ET,Aspose 写入的隐形水印就是这个形态),getTextContent会抛出Cannot read properties of null (reading 'name')。pdf.js 5.7.284(当前依赖)和 6.4.299(最新)都能复现。我在本机 343 份券商研报及其译本中扫到 90 页受影响。本 PR 把每页的文字提取放进单独的 try/catch,和现有的算子表处理方式一致:
textError,标为visibilityUnverified: true、blank: false,其余页照常检查;整份文件打不开(如InvalidPDFException)时仍整体失败。textError。inspect_pdf的 warning 写明哪几页是“解析器读不出文字”,工具说明补上textError的判读方法。INSPECT_FAILED的提示不再断言是生成环节的问题:先用其他阅读器确认,确实打不开或内容缺失时再重做。变更类型
fix缺陷修复范围
reviewPdfUtilityProcess逐页容错;进程协议与 MCP 类型新增可选字段textError;inspect_pdf的 warning、工具说明和失败提示。extract作业(它读的是交付物正文,失败语义不同,保持原样)。INSPECT_FAILED,而是返回verdict: "warning"并指出页码。UI 变化
不涉及。
怎么验证的
自动验证
修复前,新增的
pdfInspect.test.ts用例失败,报错为Cannot read properties of null (reading 'name');修复后通过。测试价值
inspectPdfPages(真实 pdf.js 解析手写 PDF)。第 2 页用BT /F1 0 Tf (mark) Tj ET,断言该页得到textError和visibilityUnverified、blank为 false,第 1、3 页照常输出文字。getTextContent在字号为 0 且尚未设字体时访问null.name;此前一页出错就让整个inspect_pdf失败,并误导模型重做产物。getOperatorList),没有覆盖文字提取失败。BT /F1 0 Tf (mark) Tj ET。reviewPdfProcess.test.ts在已有的透传用例里加上textError,保护跨进程字段不被校验丢弃。cindyDocsMcpServer.test.ts新增一条表驱动用例,验证 warning 文案和blankPages。pdfInspect.test.ts约 25ms,reviewPdfProcess.test.ts约 280ms,cindyDocsMcpServer.test.ts整文件约 2.9s。手工验证
用本机 pdf.js 5.7.284 和同样的
getDocument参数检查 343 份研报 PDF:修复前 90 页抛错;在 pdf.js 内部把该比较改成可选访问后,0 页抛错。说明这一处就是全部来源。未执行的验证
apps/desktoptypecheck:本地浅克隆缺少@cindy/device-link,apps/mobile有 7 个与本改动无关的 TS 错误;涉及文件没有报错。reviewPdfProcess.ts第 8 行原有ReviewPdfPageInspection的 unused-import lint 报错,在 main 上就存在,本 PR 未处理。风险
风险分类
textError)影响与回滚
inspect_pdf结构检查。以前整体失败的文件现在返回逐页结果和 warning;能正常解析的文件结果不变。提交前检查