· engineering· 约 21 分钟精读

Slingguard Inspection Checklist Boolean Granularity — Technical Analysis | KeyRotate Technology

核心要点速览 · TL;DR 概要

吊索具的报废判据大多是带阈值的量——链环伸长超过 5%、直径磨损超过 10%、一个捻距内断丝十根。SlingGuard 的检验表单只提供五个布尔勾选。本文把这十七条判据逐条落到五个字段上,量出哪些条目没有位置、哪些结论不看清单,以及一份写满「全部为正面」的 PDF 到底记录了什么。

Slingguard Inspection Checklist Boolean Granularity — Technical Analysis | KeyRotate Technology

港口工具间的折叠桌上放着一台平板。检验员在登记册里点开一条编号 SL-101 的扁平吊带,按下「Record Inspection」,屏幕弹出一张表单:上半部分是设备信息,中间是一组开关,下半部分是结论、缺陷描述与签字。他从上往下看了一遍,五条开关全绿,于是滑到底部,选「PASS」,填写检验依据,勾选确认,保存。

整个过程里,他没有在任何输入框里填过一个数字。

这不是操作习惯的问题。把 InspectionEntryView.swift(242 行)从头读到尾,表单里根本不存在数值输入位:五个 Toggle 绑定的都是 Bool,日期是 DatePicker,检验类型是三成员枚举,检验员姓名与资质编号是两个 TextField,检验依据、缺陷描述、处置措施是三个自由文本。整张表单没有一个小数框,没有一个整数计数器,没有单位选择器。

于是问题变成两个:这五个布尔量能装下多少现场观察;装不下的部分,最终落在哪张纸上。

本文的全部结论来自源码逐行核对,涉及 InspectionEntryView.swift、InspectionRecord.swift(258 行)、BatchInspectionView.swift(225 行)、RegulatoryHandbookView.swift、ReportExporter.swift(294 行)、CSVExporter.swift 与 RiggingAsset.swift。文中不引用任何界面观感作为论据。

一、表单上到底有什么

「Recorded Checklist」一节下面就是那五条。字段名、界面文案与初值如下。

序号界面文案字段名类型初值
1ID Tag & WLL Legible & AttachedtagLegibleBooltrue
2Free of Cuts, Tears, Burns & MeltingnoCutsOrBurnsBooltrue
3No Elongation, Stretch, Bends or CracksnoDistortionOrStretchBooltrue
4Free of Severe Corrosion, Pitting & GougesnoCorrosionOrPittingBooltrue
5Overall Structural Visual Check PassedvisualInspectionPassBooltrue

五条全部默认打开。表单打开的那一刻,它已经在说「五项都没有问题」,而检验员一个字还没输入。这一节的小字脚注写得很克制:「Record observations made under the procedure actually used. SlingGuard does not select or validate an applicable inspection standard.」意思是这些格子记录的是按某个程序做出的观察,应用既不选程序,也不验程序。脚注是对的,但它只出现在屏幕底部,不会被写进任何一条记录。

同一组五个 @State 在 BatchInspectionView.swift 里原样重复了一遍,初值也一样。批量检验与单件检验共用同一份清单,这一点在后文还会用到。

二、三个结论与保存闸门

InspectionOutcome 三个成员,rawValue 分别是 PASS (In Service)、QUARANTINE (Repairs / Load Test)、SCRAP (Decommission & Destroy)。表单一打开,结论的初值是 .pass。

能不能保存由一行表达式决定:confirmsEntry && prospectiveRecord.isEvidenceCompleteForReporting。前半段是底部那个「确认」勾选,后半段展开成 reportingGaps.isEmpty。缺口清单按结论分档:

结论必须补齐的项五个勾选在其中的角色
通过检验依据、条目确认、清单无负面发现唯一的必要条件
隔离检验依据、条目确认、缺陷、处置、期限不参与
报废检验依据、条目确认、缺陷、处置不参与

这张表是全文的枢轴。五个布尔量只在「通过」这一支被当作必要条件;对「隔离」与「报废」,代码既不要求它们为真,也不要求其中至少一项为假。reportingGaps 的计算里,hasPassingChecklist 只出现在 case .pass 分支下,另外两支一个字都没提清单。

换句话说,清单是一道只守一个门的闸门。

三、手册里的十七条

RegulatoryHandbookView 用五个标签页装下全部参考内容:合成纤维、合金链条、钢丝绳索、挂法与夹角、法定框架。前三个标签页各自列出一组报废条目(合成纤维页的标题是 Mandatory Removal / Discard Criteria,另两页是 Statutory Discard Criteria),合计十七条:

合成纤维七条——标签缺失或不可读、酸碱灼伤、熔融或炭化(超过 90 ℃ 或焊渣)、撕裂破洞、缝线断裂、打结、紫外老化。

合金链条五条——链环伸长超过 5%、直径磨损超过 10%、刻痕裂纹、扭转变形、超过 400 ℃ 的热暴露。

钢丝绳索五条——一个捻距内十根随机断丝或单股五根断丝、扭结与死弯、股绳散开(鸟笼状)、绳芯外露、端接件损伤(弗莱明眼套开裂、压接松动、钩口张开)。

这十七条是应用内对报废判据的唯一完整表述。它们在源码里的形态是 SwiftUI 视图中的 Text 字符串,bulletPoint(bold:text:) 一个个拼出来,不是枚举,不是常量数组,也不被任何判定函数引用。

四、十七条落进五个格子

把手册条目按语义往五个字段上靠,能落成下面这样。左列是手册条目,右列是它能被记录的位置。

手册条目唯一可落的位置
标签缺失或不可读标签可读
酸碱灼伤无切割烧灼
熔融或炭化无切割烧灼
撕裂、破洞无切割烧灼
缝线断裂整体外观
打结整体外观
紫外老化整体外观
链环伸长超过 5%无形变伸长
扭转变形无形变伸长
扭结与死弯无形变伸长
鸟笼状散股整体外观
直径磨损超过 10%无腐蚀点蚀
刻痕与裂纹无腐蚀点蚀
热暴露超过 400 ℃整体外观
一个捻距内断丝十根整体外观
绳芯外露整体外观
端接件损伤整体外观

十七条里有八条只能落进「整体外观」这一格。这一格是五个字段中最没有诊断力的一个:它把「缝线断了一针」与「一个捻距断了十根钢丝」压成同一个布尔值,也把「打过一次结」与「端接件开裂」压成同一个布尔值。

另有三条判据带明确的数值门槛:链环伸长 5%、直径磨损 10%、一个捻距内断丝十根。表单里没有为它们准备任何数值位,能记的只是所在那一格的真或假——「有形变」「有腐蚀」「整体外观未通过」,具体读数多少,无处可写。

十七条判据,五个勾选,一个表单手册按材料分三族列条目;表单对七类器具只有同一个版本合成纤维 七条合金链条 五条钢丝绳 五条手册里是正文,不是常量手册条目17表单勾选5标签可读tagLegible无切割烧灼noCutsOrBurns无形变伸长noDistortionOrStretch无腐蚀点蚀noCorrosionOrPitting整体外观visualInspectionPass三种结论的入参通过五项全真才可保存隔离缺陷·处置·期限报废缺陷·处置即可后两支不看清单卸扣、吊环、主环在手册里没有对应条目,却共用同一张检验表单

五、被压掉的是数值

以链环伸长为例。判据是相对量:

ε=L1−L0L0>5%\varepsilon = \frac{L_{1}-L_{0}}{L_{0}} > 5\%

其中 L0L_{0} 是原始内节距,L1L_{1} 是实测内节距。要判定,得先有两个长度。表单里没有 L0L_{0} 的位置,也没有 L1L_{1} 的位置,更没有卡尺读数与测点说明。检验员能做的只有一件事:量完之后自己判断,然后把「无形变伸长」关掉或留着。

直径磨损同理。判据是磨损量相对公称直径的比例,而磨损沿链环周向并不均匀,测点选在受力面还是侧面,结果差得很多。断丝计数同理:一个捻距的长度随绳径与捻距倍数变化,不同检验员对「一个捻距」的取法未必一致,十根这个阈值离开捻距定义就没有意义。

一个布尔量最多一比特。一条带阈值的判据,有效信息是「读数、阈值、比较方向、测点」,压成一个比特之后是不可逆的。下一位检验员翻开这条记录,看到的是「合格」两个字,看不到这次是 5.2% 还是 6.1%。没有这两个数,就无法判断磨损速率,也无法在两次检验之间做趋势比较——而这恰恰是定期检验相对于一次性验收的全部价值。

这里要说清楚:字段设计成这样,不等于应用在撒谎。记录如实反映了「检验员认为合格」这个判断。问题在于,当这条记录被当成证据使用时,读它的人会默认它承载了判据本身。

六、七类器具,一张表单

RiggingType 七个成员:扁平吊带、圆形吊带、链条吊索、钢丝绳索、卸扣、吊环与吊装环、主环与连接件。

InspectionEntryView.swift 全文没有出现过 equipmentType 这个词。表单不知道自己在检验什么:头部只显示编号、名称与额定载荷,五条开关对七类器具一字不差。

后果是具体的。「Free of Cuts, Tears, Burns & Melting」这一条对吊带是核心判据,对卸扣却近乎空转——卸扣没有织物可以割伤、撕裂或熔融,它的报废判据是销轴螺纹损伤、弓体接触面磨损、本体变形与裂纹。这些在五格里没有位置,在手册里也没有对应章节:手册的报废判据只覆盖合成纤维、合金链条、钢丝绳索三族,卸扣、吊环、主环三类器具在手册中没有任何一条报废条目。

于是出现一个错位:手册覆盖三类材料,表单覆盖七类器具,两者的交集只有三类。对另外三类器具,检验员手上既没有判据条目,也没有专用字段,只有五个为织物写的开关。

七、勾选如何改写结论

五条 Toggle 各挂了一个 onChange,回调都指向同一个函数:

if !allChecksPassed && outcome == .pass { outcome = .quarantine }
else if allChecksPassed && outcome == .quarantine { outcome = .pass }

这段代码有三个可直接观察的后果。

第一,改写是双向的。任一项被关掉,且当前结论是通过,结论自动变成隔离;反过来,五项全部打开,且当前结论是隔离,结论会自动变回通过。第二条分支的用意大概是「改错了要能改回来」,但它同时意味着:检验员为了看清界面先把某一项关掉、再打开,落盘的结论会被静默改回通过。

第二,改写只覆盖两个状态。报废不在规则里:把结论选成报废之后再动任何一条开关,结论都不变。清单与报废之间没有任何约束关系。

第三,结果对操作顺序敏感。同一组最终值,先选隔离再动开关,与先动开关再选隔离,落盘结论可能不同——因为函数只在开关变化时被调用,结论选择器本身不触发重新裁决。

八、一条报废记录的清单可以是全真

把上面几条拼起来,能得到一条完全合规的录入路径:五项开关全部保持为真,结论选「报废」,缺陷描述写「端部压接套开裂,见照片」,处置写「现场剪断并送废料箱」。reportingGaps 检查的是检验依据、条目确认、缺陷、处置四项,全部满足,于是 canSave 为真,记录落盘。

导出 PDF 时,「Checklist entries」一段取的是 checklistFindings.isEmpty 的分支,打印一句「All recorded checklist entries were marked positively.」同一页上,结论行写着 SCRAP (Decommission & Destroy)。

这两句话并不矛盾,它们只是描述了两个不同的面:清单描述五类可见征象,报废理由可能在这些征象之外,也可能在之内。但当理由在之内时——比如链环已经伸长到 8%——检验员同样只能把「无形变伸长」关掉,用一格否定表达一个连续量,然后在缺陷描述里补一句「伸长约 8%」。数值以散文形式存在,不进结构,不进 CSV,也不参与任何计算。

九、同一组布尔量的三种出口

同一份记录,三个出口的粒度并不相同。

JSON 落盘时,五个布尔量是必填键,解码器用 try container.decode(Bool.self, ...) 逐个读取;缺一个键,整个快照解码失败。这是最严格的一层。

CSV 导出时,五个量是五列独立布尔:Tag Legible、No Cuts Or Burns、No Distortion Or Stretch、No Corrosion Or Pitting、Visual Inspection Pass。机器可读,粒度最细。

PDF 导出时,五列变成一段散文。全真时是一句概括,有发现时是若干条句子,例如「Distortion, stretch, bends, or cracks recorded」。没有逐项表格,没有「未记录」这一状态。

结构化程度最高的出口(CSV)恰恰最少被人拿去看;最常被交给客户与监管者的 PDF,反而把五格压成了一句话。而这句话只在全真时出现,它描述的实际内容是「没有记录到负面」,不是「检查了五项」。

十、另一个应用把「没记录」存成了一个值

同一套产品矩阵里,TagWorks 的记录结构选了另一条路。它的目视结果是 VisualInspectionResult?——可空的两成员枚举,nil 表示这条历史记录的目视检验没有记录,读取端据此显示「未记录」而不是「无缺陷」。测量是三个 Double?:保护接地连续性、绝缘电阻、负载电流,判定由 TestThresholds.evaluate 这个纯函数按器具类别算。

差别不在谁更严谨,而在对「未记录」的建模。一个把「没记」当成合法状态显式保存,另一个把「没动过」默认成「通过」。五个布尔量没有第三态,也就没有地方安放「这项我没看」。

十一、五条可以落地的改动

第一,清单按器具族下放。选定器具类型后加载对应的判据子集:织物走织物条目,链条走链条条目,卸扣、吊环、主环补上各自的条目。公共项(标签可读)抽出来做公共段,其余不再共用。

第二,每一项改成三态。合格、不合格、未检查,或者直接用 Bool?。未检查不得计入通过判定,也不得被序列化成 false 冒充否定。

第三,给三条数值判据加数值位。伸长百分比、直径磨损百分比、单捻距断丝根数,各自带单位与一位小数。布尔值由读数派生,而不是代替读数;原始读数同时保留,用于下次比较。

第四,结论与清单解耦。清单只产出发现项,结论由检验员选择;取消「勾回去就自动恢复通过」的隐式改写,改成显式提示加二次确认。

第五,报告逐项打印。把五格(或扩展后的判据表)按项列出,标明「记录为合格」「记录为不合格」「未记录」,而不是在全真时打印一句概括。CSV 与 PDF 用同一份投影函数生成,避免两个出口各说一套。

十二、能力边界

  • 五个布尔量记录的是检验员对五类征象的判断,不是判据完备的证明。
  • 应用不判断器具类型与判据族是否匹配,七类器具共用一张表单。
  • 没有原始读数,就没有复算,也没有趋势;这条记录无法支撑磨损速率一类的推论。
  • 自动改写只覆盖通过与否决两个状态,不构成完整状态机,且对操作顺序敏感。
  • 报废与隔离两支不看清单,一份全真的清单可以与报废结论并存。
  • 报告复述的是记录内容,不构成法定检验证书;应用不选择也不校验检验规程。

十三、结语

五个勾选框不是偷懒的结果,它是一次真实的取舍:现场要快,界面要小,检验员不该在手机上敲十六个数字。这个取舍在多数时候成立——一条明显割伤的吊带,关掉一格就够了。

问题出在边界上。当判据本身是连续量,而记录只有两个状态,中间那段就被挤进了自由文本;当下一位读者打开这条记录,他拿到的是一个结论,而不是一个可以复核的过程。端侧离线工具的价值本就在于把现场固定下来,固定的前提是先约定:这一格代表什么,缺省值算不算证据,没有记录与记录为合格是不是同一件事。

把这三件事分开,五个格子才真正开始工作。

参考资料

Share:
Back to Blog