元数据、质量验证与项目
本节目标
把前四节落成一个可运行、可回归、明确标注能力边界的小项目;能从清单还原输入版本、解析器、配置、元素位置与失败原因,并设计自动门禁和人工验收。
三层元数据
来源层
- 业务
document_id与内容版本source_id; - 原 URI 或受控相对路径;
raw_sha256、大小、获取状态;- 来源系统、权限标签、有效期;
- 声明类型与检测类型。
解析层
- parser/adapter 名称、版本和配置哈希;
- 运行状态、错误码、警告和资源用量;
- 规范化规则版本;
- 父源版本与派生产物哈希。
元素层
element_id、kind、order;- page/line/bbox 等位置;
section_path与结构来源;- 文本哈希、表格/代码属性;
- 权限继承与人工复核状态。
本项目只展示其中可由离线文件检查器确定的字段。生产系统还需加入业务身份、权限、时间与隔离运行记录。
质量不是一个分数
| 维度 | 自动信号示例 | 人工验收示例 |
|---|---|---|
| 完整性 | 文件/页/元素数、空页率 | 是否漏了附录和图注 |
| 正确性 | 非法字符、表格列数、字段校验 | 金额、公式、否定词是否正确 |
| 顺序/结构 | order 唯一、标题层级、重复页眉 | 双栏阅读顺序是否自然 |
| 可追溯性 | 位置字段完整、哈希可重算 | 能否快速回到原页原区域 |
| 稳定性 | 相同输入/配置输出相同 | 版本升级差异是否可解释 |
| 安全性 | 类型冲突、超限、符号链接 | 权限、提示注入和敏感内容治理 |
自动指标主要发现症状。对关键场景仍需分层 gold set,并记录标注规范、样本版本与评审人一致性。
项目能力契约
项目包含:
- inspect_documents.py:只读扫描器;
- test_inspect_documents.py:27 项标准库回归测试;
- document-manifest.schema.json:输出契约。
已实现:
- 按允许扩展名、magic bytes、HTML 内容特征和 ZIP 容器签名路由;
- 拒绝“PDF 后缀 + HTML 内容”等冲突;
- UTF-8/UTF-8 BOM/UTF-16 BOM 严格解码与 LF + NFC 规范化;
- Markdown、HTML、CSV、JSON 和纯文本的最小结构元素;
- JSON 重复键和非有限数值拒绝,CSV 嵌入逗号/换行处理;
- 相对路径、源哈希、配置哈希、
parse_revision_sha256、元素哈希、显式 coordinate space、行范围和标题路径;parse revision 绑定 raw hash、parser name/version 与 config hash,element ID 再绑定 parse revision、kind、位置与文本哈希; - 文件数、单文件和总字节预算,符号链接不跟随;
stat()预检查后会用有界读取再次执行预算,应用层最多请求上限外一字节,发现增长便拒绝; pass、review_required、fail三态门禁和确定性输出。
明确未实现:
- PDF/Office/图片内容解析、OCR、VLM、容器展开;
- 操作系统沙箱、杀毒、内容消毒和权限系统;有界读取也不能替代抗 TOCTOU 的受控文件描述符或隔离执行环境;
- 浏览器级 HTML 容错、CSS 版面、完整 Markdown 方言;
- 自动编码猜测、语言识别、生产级并发与时间/内存强制隔离。
这些“未实现”是接口边界,不是待隐藏的问题。遇到相关格式时清单返回 external_adapter_required,不会产生伪文本。
第一次运行
在项目根目录(同时包含 docs/ 与 .website/)使用 PowerShell 7:
$project = '.\docs\文档解析\examples'
$sample = Join-Path $env:TEMP 'document-inspector-sample'
$report = Join-Path $env:TEMP 'document-inspector-report.json'
New-Item -ItemType Directory -Path $sample -Force | Out-Null
Set-Content -LiteralPath (Join-Path $sample 'guide.md') -Encoding utf8 -Value "# 超时`n`n请求必须设置超时。"
Set-Content -LiteralPath (Join-Path $sample 'cases.csv') -Encoding utf8 -Value 'name,note','A,"含,逗号"'
py -3.11 -B "$project\inspect_documents.py" $sample --output $report
$manifest = Get-Content -LiteralPath $report -Raw -Encoding utf8 | ConvertFrom-Json
$manifest.summary | Format-List所有输入都在支持范围内、成功解析且没有 warning 时,进程退出码为 0,summary.gate 为 pass。输出必须位于输入目录之外,避免下一次扫描把自己的清单当成新输入。
加入 PDF、DOCX、PNG 或 ZIP 后,清单会记录 external_adapter_required;UTF-16、BOM 或受控字符等警告也要求复核。此时门禁为 review_required,进程退出码为 2。类型冲突、解码失败、未知扩展名或资源超限会得到 fail。退出码 2 不代表程序崩溃,而是要求调用方显式处理未发布状态。
运行回归测试
$env:PYTHONDONTWRITEBYTECODE = '1'
Push-Location '.\docs\文档解析\examples'
try {
py -3.11 -B -W error -m unittest -v test_inspect_documents.py
py -3.11 -B -O -W error -m unittest -v test_inspect_documents.py
} finally {
Pop-Location
}27 项测试覆盖正常路径和失败路径,包括:Markdown 结构与 NFC、CSV 引号/换行、JSON 重复键/NaN、UTF-16 边界、非法 UTF-8、HTML 脚本忽略、格式伪装、PDF/OOXML 分流、未知扩展名、三类资源上限、读取阶段的字节预算、输出确定性、parse revision/element 身份重算、哈希变更、路径隐私和输出位置限制。
-O 会移除 Python 的 assert 语句,因此生产门禁不能写成裸 assert。本实现用显式异常和状态;测试仍使用 unittest 的断言方法。
完成本项目后,用来源到引用证据链项目把 parse revision 与 canonical revision、chunk/index generation 和最终 source-span citation 接起来;本页的独立 manifest 仍不包含业务 document ID、ACL 生命周期或发布指针。
如何读清单
先看 summary.gate,再逐文档检查:
extension_media_type与detected_media_type是否一致;status是否允许发布;issues是 warning 还是 error;raw_sha256、parser/version 与config_sha256是否能定位版本;- 元素的
order、location、section_path和text_sha256是否完整; - 用相同输入重跑,比较 JSON 是否完全一致。
不要只统计 parsed 数量。一个文档即使成功生成元素,仍可能在真实语义上乱序或表格错位;项目没有替代 gold set。
综合任务:接入一个受控 PDF 适配器
在不改变核心清单 schema 的前提下,设计一个适配器(可以先写接口与假实现):
- 输入必须包含受控文件句柄/内容版本、页数上限、超时、解析配置和权限上下文;
- 输出包含逐页元素、页码/bbox、parser 版本、警告与资源使用;
- 数字页面先原生抽取,扫描页面进入 OCR;
- OCR 缓存键包含页面哈希、DPI、语言包、引擎和版本;
- 类型冲突、加密、损坏、超时、零文本、低质量分别有状态;
- 用至少 12 页分层 gold set 验证,不把真实敏感文件提交到仓库。
完成定义:同一输入与配置可重放;每个元素能回到原页;外部服务不可用时不会把部分结果发布;关键表格和字段经过人工抽查。
扩展练习
- 先写测试,再为 TSV 增加显式扩展名和分隔符契约;不得自动猜任意方言。
- 为 HTML 未闭合块和 Markdown 标题跳级新增警告,同时保持输出确定性。
- 写一个 schema 验证步骤;若引入
jsonschema,先放进独立venv,不要把环境提交进 vault。 - 为真实业务设计
document_id与source_id的映射和权限继承。
掌握检查
- 我能解释清单每一层哈希的对象和用途。
- 我能区分语法解析成功、质量通过和可发布三件事。
- 我能读懂
pass/review_required/fail,且不会忽略非零退出码。 - 我能为新增格式写成功、伪装、损坏、超限和确定性测试。
- 我能明确陈述标准库项目没有验证 PDF/OCR 内容质量。
- 我能设计自动指标与人工 gold set 的组合验收。