TT Lab
开始
学习 学习路径 课程

保险领域进阶

同一张收据用了两次,只是文件名不同

在 TT Lab 中继续学习

一句话总结

理赔证明材料的检查,不是清点文件是否到齐,而是依据内容而不是名称来判定这个文件是否真的是那份材料。格式用魔数(magic bytes)判断,同一性用内容哈希判断,记录与实物之间的偏差则通过双向比对来发现。

为什么需要它

在保险理赔中,材料是赔付判断的依据。但受理柜台有多个、渠道有多个时,进入同一系统的文件状态就会五花八门。扫描仪生成的 PNG 被经办人加上 .pdf 后传上来,文件名里带着被保险人的姓名,同一张收据只改了名字就提交到两笔索赔中。审核人员只看界面上能打开的东西,所以这三种情况用肉眼都很难发现。

把检查交给人的眼睛,三件事会同时失守:材料没到齐却被当作到齐处理(赔付依据缺失),同一份材料两次被用作赔付依据(重复赔付),文件名中携带的个人信息扩散到清单、备份和日志中。这三件事一旦事后才发现,补救的代价都非常高。相反,在受理时点做自动检查则很便宜——所需要的只是一张规则表、文件开头的几个字节,以及哈希。

工作原理

检查清单作为数据,而不是代码。每种索赔类型所需的材料不同,这份清单会随产品和规定的变化而变动。把类型和材料种类放进一张有两列的表中,检查程序只需要读这张表,规定变了也不用改代码。像 SQLite 这样列类型比较宽松的存储,最好同时了解值的存储类别是什么(SQLite 数据类型)。

格式根据开头的字节来区分。扩展名是人加上的标签,没有任何保证。PDF 以 %PDF- 开头,这一点由 RFC 8118 的媒体类型注册条目明确规定;PNG 的前八个字节用十进制表示是 137 80 78 71 13 10 26 10,这由 RFC 2083 第 3.1 节定义。JPEG 以 FF D8 FF 开头,ZIP 则是 PK 后面跟着 03 04。Linux 的 file 命令所做的事,归根结底也是查看这张表。

这里有一点必须遵守。这些文件中混有 NUL 字节,所以不能使用 grep。GNU grep 会把混有 NUL 的输入视为二进制文件,只输出“Binary file matches”,或者悄悄地什么也找不到。以 NUL 开头的格式,越是如此,越会与真实文件明显不符。请用 od -c 查看,或者在 Python 中用 open(path, "rb").read(16) 读取后比较。

同一性依据内容哈希来判断。靠文件名绝对无法判断是不是同一份材料。用 hashlib 求出文件内容的 sha256,把值相同的归为一组,改名后重新提交的材料就会作为一组显现出来。把哈希写进供人阅读的清单时,通常用十六进制书写;需要把字节原样放入文本时,整理了 base16、base32、base64 各自适用场合的文档是 RFC 4648。处理路径的代码,如果使用 pathlib 而不是字符串运算,可以减少区分扩展名和名称时的失误。

记录与实物要双向比对。受理记录中有而文件不存在,与文件存在而记录中没有,是两种不同的事故。前者是赔付依据空缺,后者是留下了不知属于谁的个人信息。只看一个方向的检查程序,总会漏掉一半。

doc_rule(규칙표) ─┐
                  ├─▶ 빠진 서류      ─┐
submission(기록) ─┤                    ├─▶ 청구별 보완 요청 목록
                  ├─▶ 고아 / 없는 파일 ┤
inbox(실물) ──────┴─▶ 형식 · 해시 · 이름 ┘

在现场相遇的样子

把期限的起算日弄错,是非常常见的情况。如果以受理日期为基准来计数,受理越晚的案件,期限就越长。起算日应当是事故日期,这条规则要用一行文字写下来,与检查程序放在一起。本实验以事故日期起 30 天作为期限,这不是实际的法定期限,而是本实验的假设。每个产品和每家公司都不同,所以在现场必须确认该公司的规定。

文件名中的个人信息也经常原样留存。内容做了去标识化处理,却不动文件名的情况很多,而清单界面、备份索引、错误日志,甚至报告的文件名,都会原样携带这个名字。为了避免检查报告本身再次传播同样的值,报告中只写笔数和规则,不写具体的值。

实际工作中真正重要的事

下一项实验要做什么

你将亲自创建 Daon 财产保险(虚构)的 60 笔索赔和收件箱中的 189 个文件,并用规则表找出缺失的材料。编写不相信扩展名的格式判定程序,给出整个收件箱的判定表,用内容哈希把被重新使用的材料归为一组,并统计文件名中携带的个人信息。从事故日期起计算期限,把记录和实物双向比对之后,以各笔索赔的补充要求清单和报告收尾。