摘要
读取战斗日志(Logs,按时间列出“谁对谁做了什么”的面板)时,OCR 会对同一行读多次,程序再决定是输出这行文字,还是保持“未知”。有一些私有的实验规则会把原本“未知”的行升级成输出文字。为了防止这类升级引入错误,之前已经写过一个“保存结果完整性检查器”(v2):拿基线结果和候选结果对比,检查没有偷偷改原框、没有丢原始读数等。
本实验发现 v2 有一个软件漏洞:如果原始读数里藏着一些不常见的换行或分隔控制字符(垂直制表、换页、Unicode 行/段分隔符等),文字规范化和去首尾空白会把它们“抹掉”,于是一个其实跨了两行、或者名字中间被切断的读数也能被接受。另外,v2 判断升级资格时还在用“删掉所有空白再比较”的旧规则,可能让删空格掩盖名字或数字的变化。
v3 在不改动 v2 冻结代码的前提下叠加两道检查。64 个合成用例里,旧版误收的 42 个无效用例 v3 全部拒绝;对 6 份已保存的真实结果做一次检查,全部仍然有效。这是软件完整性检查,不是 OCR 准确率。
要回答的问题
- 能否堵上“控制字符被规范化隐藏”和“删空格掩盖语义变化”两个漏洞,同时保留 v2 的所有拒绝?
- 已有的真实保存结果在更严格的检查下是否仍然有效?
数据与来源
- 合成用例 64 个:16 个合法对照、48 个必须拒绝的要求。其中包括 10 种行边界字符在开头/结尾/名字内部三种位置、4 个合法的规范化/空格对照、2 个“未知行带边界字符”的对照,以及之前 28 个语义空格用例。之前的 56 条兼容性要求作为回归用例保留。
- 6 对已有的真实保存结果(基线 JSON + 候选 JSON),来自之前的日志实验,都是已曝光的开发来源。
- 不读取图片、不解码视频、不跑 OCR、不读评分参考。
方法
v3 = v2 + 两道附加检查,只返回“有效/无效”和原因,绝不生成替换文字或新结论:
- 原始读数边界检查:对每一条将要输出文字的日志行,只要它的任何一次原始读数含有 CR、LF、VT、FF、FS、GS、RS、NEL、LS、PS 这些行/分隔字符,就拒绝——在把规范化后的文字当作证据之前就检查。不删分隔符、不修复。仍保持“未知”的行不做这项检查:坏读数可以作为可见证据留着,只要不输出文字。回合标题沿用 v2 规则。
- 语义空格检查:对每个 v2 认为有效的私有升级,再套用之前冻结的语义空格规则:名字、玩家名、法术名、数字和语法词必须原样连续,不允许用删空格来掩盖玩家/单位/标签或数字的变化。
设计和用例都在一次正式检查之前冻结。
设置
在一个新的输出目录保存一次检查结果;分别报告基线输出行、升级行和未变行,以及附加检查的调用次数和耗时(耗时不是 CPU 成本或图片延迟)。
结果
合成用例
| 项 | 数 |
|---|---|
| 用例总数 | 64 |
| 合法对照 | 16 |
| 必须拒绝 | 48 |
| 与预期不符 | 0 |
| 旧版误收的无效用例 | 42 |
| 新版误收的无效用例 | 0 |
| 新拒绝:边界字符 | 24 |
| 新拒绝:语义空格 | 18 |
24 个新拒绝的边界用例就是 VT、FF、FS、GS、RS、NEL、LS、PS 各在开头/结尾/内部三种位置(CR 和 LF 旧版本来就拒绝)。18 个语义用例包括主体/玩家/法术/行动者/目标/能力/效果名中空格被删或插入、伤害/死亡数/括号/持续时间/时钟/谓词被拆开、括号内加空格、跨行合并等。
6 份已保存结果
| 结果 | 行 | 基线输出行 | 候选输出行 | 验证的升级 | 未变 |
|---|---|---|---|---|---|
| 短页(5 行) | 6 | 2 | 5 | 3 | 3 |
| 战场负例 | 0 | 0 | 0 | 0 | 0 |
| 滚动页(29 行) | 29 | 17 | 27 | 10 | 19 |
| 洞穴页 | 7 | 5 | 5 | 0 | 7 |
| 英雄面板负例 | 0 | 0 | 0 | 0 | 0 |
| 说明框负例 | 0 | 0 | 0 | 0 | 0 |
6 份全部仍然有效。合计:基线输出 24 行、验证升级 13 行、候选输出 37 行、未变 29 行;42 个原生框、126 次原始读数全部保留;37 条输出行做了边界检查,13 个升级做了语义检查。合成检查约 0.019 秒,保存结果检查约 0.005 秒。
新增软件测试 125 项、相关回归 433 项,共 558 项通过。
作为背景,之前的报告(本实验没有重读或重算)记录这批日志可读完整行 36/39 正确、可核验的输出 36/36 正确。
失败与负结果
v2 的漏洞本身就是负结果:42 个本应拒绝的合成用例被旧版接受。本实验没有发现新的真实读数因 v3 被拒——但这只说明这 6 份已保存结果里没有这类问题。
局限
- 这些是软件验证要求,不是测量到的 OCR 失败。
- 同一个 OCR 引擎多次读出相同的错字,可以通过所有完整性检查。
- 6 份结果来自已曝光的开发来源,不是盲测。
- 没有记录独立的主线验收;没有生产改动。
结论与下一步
v3 堵上了两个可能让错误读数“看起来干净”的漏洞,并保留了 v2 的全部拒绝和所有原始证据。它只能保证“输出没有作弊”,不能保证“读对了”;真正的读取质量仍需在新图片上独立验收。
Comments