跳转到内容

标准件开源库整合:可二次开发的基底设计

状态:Research Note 版本:0.1.0 日期:2026-09-08 研究问题:把 BOLTS、bd_warehouse、cq_warehouse、FreeCAD Fasteners WB 四个开源库整合成一个 Aira 可以二次开发的基底,需要什么规范数据模型、什么摄取管线、几何层落在哪里、许可边界在哪里? 前置调研:标准件库来源搜集 对应文档:产品宪法、AMIR v0.1、CAD 基线与维护边界 后续变化(2026-09-14):M1 公共产品结构已于 2026-09-13 落地(方案、状态),本文两处前提随之移动,正文保留原判—— ① §7 末段“BOM、替换、实例共享需要 assembly.compose 落地”:该 op 从未实现,这些能力改经 set-product 取得,零件仍是库函数、不升为 operation 的结论不变,且 build-program 现可按 bodyId 建立多个 Body,零件程序与主体程序可各成定义;② §9”不做 STEP 目录导入:AMIR v0.1 无 STEP import“的理由已不成立(imported-brep / imported-product 已是计划步骤),不取商业目录与不复制上游 builder 的结论另有许可与职责依据,不受影响。

前一篇是来源普查,本篇是源码级取证与整合设计。四个库已按 depth-1 只读克隆到会话临时目录做实测, 未进入仓库,也未写入 third_party/reference-sources/SOURCES.lock.json。本文不授权实施。

  1. BOLTS 的数据不是 GPL。 仓库根 LICENSE 是 GPL-3.0(覆盖工具链与 backends),bolttools/ 是 LGPL-2.1, 而 18 个数据集合逐个声明自己的许可:13 个 LGPL 2.1+、4 个 MIT、1 个 Unlicense。 全部机械标准件(bearings、hex、hex_socket、nut、washer、6 类型材)都在 LGPL 2.1+ 那一档。[实测]
  2. BOLTS 是唯一带标准本体的源:94 个标准号,带 body / status(active/withdrawn)/ replaces 关系, 7 种参数类型(Length (mm) 360 处、Table Index 73、Length (in) 16、String 11、Number 2、Bool 1、Angle (deg) 1), 支持一维与二维表,且 bolttools/common.py 的 Parameters.union() 把“参数集合合并”定义成带类型兼容检查的操作。
  3. bd_warehouse 是 cq_warehouse 的严格超集,同为 Apache-2.0、同一作者:48 个 CSV / 1752 行 对 34 个 / 930 行, 多出 O 形圈(349 行)、挡圈 DIN 471/472(174 行)、轴键、ISO 228-1 管螺纹等 14 个文件。cq_warehouse 可以整体弃用。
  4. FastenersWB 覆盖最全但许可最差:192 个文件、分节后 400 张表、7883 行,ISO 93 个文件、DIN 39、ASME 32, 许可 GPL-2.0。它是校验源,不是取用源。
  5. 阻塞级发现一:同名不同义。 cq_warehouse 的 iso7089:h 系统性地等于 FastenersWB 的 h_max 而非公称 h (M3 0.55/0.5、M4 0.9/0.8、M5 1.1/1.0),横跨 4 列、每列 11–15 个规格逐一吻合。 按符号名合并会静默产出厚 10% 的垫圈。规范模型的合并键必须是 (标准号, 符号, 统计量)。[实测]
  6. 阻塞级发现二:FsData 一个文件多张表。 192 个文件里 180 个含 ≥2 个表节(din103def.csv 有 71 节)。 朴素按文件解析会把 ISO4762def 和 ISO4762range 混成一张表——本次首轮解析就踩中,M3 的螺纹长 b 从 18 变成 30。 摄取必须分节。[实测]
  7. 几何层可移植,无需新绑定。 cq_warehouse 的源码注释记录了它试过 sweep 与 extrude-with-rotation 后 最终选择“从螺旋线直接构面”;维护版 Replicad 已经具备这条路径需要的全部原语: makeHelix、assembleWire、makeFace / makeNonPlanarFace、makeSolid、weldShellsAndFaces、makePolygon、makeCylinder。[实测]
  8. 发现层零改动。 third_party/maintained/replicad/scripts/generate-library-reference.mjs 从源码生成 AI 可见的 API 索引(带 upstreamCommit/sourceHash),程序沙箱 program-compartment.ts 暴露 replicad 全部非 host 导出。 往维护版 Replicad 加一个零件函数,AI 立即可发现可调用,不需要新工具、新目录、新检索执行器。
  9. 因此零件不应该是新的 AMIR operation,而应该是程序里的库调用。 新增 operation 要配 descriptor、能力条目、 naming algorithm、schema 版本与证书路径;库函数一样都不需要,且自动满足“不得另建平行执行器”。
  10. GB/T 的载体已经存在:BOLTS 用“一张表服务多个标准号”表达等价(hexbolt2 一张表同时是 ISO 4014 / DINENISO 4014 / DINEN 24014,并标 replaces: DIN931,而 DIN 931 自身标 status: withdrawn)。 GB/T 5782 只是往这张表再挂一个 designation,模型不用改。

四个库以 git clone --depth 1 克隆到会话临时目录,用 Python 直接解析原始数据文件实测,不依赖上游文档或检索摘要。 BOLTS 的 .blt 用 yaml.SafeLoader 加自定义 !include 构造器解析(型材数据经 !include 外挂在 data/profile_*/ 下); FsData 用分节解析器(单字段行 = 表名,其后第一行 = 表头)。

[待验证] 本文所有跨源数值比对只覆盖 ISO 4762 / 4032 / 7089 三个标准的公共列,以及统计量扫描能触及的列 (要求 FsData 同时存在公称列与 _min/_max/_mean 变体列,实际只有 4 列满足)。其余列未验证,不能推定一致。

源 许可 数据规模 结构 独有价值 定位
BOLTS 数据 13×LGPL 2.1+ / 4×MIT / 1×Unlicense;工具链 GPL-3.0;bolttools/ LGPL-2.1 18 集合、82 class、94 标准号、2730 行 YAML .blt,含类型系统、一维/二维表、!include 唯一的标准本体:body/status/replaces、类型化参数、union() 合并语义 骨架
bd_warehouse Apache-2.0 48 CSV、1752 行 src/bd_warehouse/data/*.csv + Python 生成器 O 形圈、挡圈、轴键、ISO 228、孔径/钻头表 主要取数源
cq_warehouse Apache-2.0 34 CSV、930 行 同上(CadQuery 版) 无——bd_warehouse 的子集 弃用
FreeCAD Fasteners WB GPL-2.0 192 文件 → 400 表、7883 行 分节 CSV,列名自带统计量 覆盖最全;_min/_max/_mean 显式 只做校验,不取用

按标准体分布:BOLTS 的 94 个标准号中 DIN 29、ISO 17、EN 8、DINENISO 8、DINEN 7、DINISO 4、ANSI 3、ASME 2、其他 16; FastenersWB 的 192 个文件中 ISO 93、DIN 39、ASME 32、其他 28。两边都没有一个 GB 文件。

4.1 统计量语义冲突(决定规范模型的形状)

Section titled “4.1 统计量语义冲突(决定规范模型的形状)”

同一个 ISO 7089 M3 垫圈厚度,三个源给出两个值:

源 符号 M3 M4 M5 实际含义
BOLTS plainwasher1 s 0.5 0.8 1.0 公称
FastenersWB iso7089def h / h_max 0.5 / 0.55 0.8 / 0.9 1.0 / 1.1 公称 / 最大
cq_warehouse iso7089:h 0.55 0.9 1.1 实为最大值

系统扫描(比对每个 cq 列与 FsData 同名列及其统计变体,取匹配数最高者)确认这是系统性的: iso7089:h、iso7090:h、iso7092:h、iso7094:h 四列全部命中 h_max,每列 10–15 个规格逐一吻合,无一例外。

结论:符号名不是合并键。 规范模型的最小合并单元必须是三元组

(standardDesignation, symbol, statistic) statistic ∈ {nominal, min, max, mean}

FastenersWB 把统计量写进列名(d1_min、d2_max、s_mean、ds_min、dk_max),机器可恢复; BOLTS 部分写(e_min、m_max、t_min),其余是公称;cq/bd_warehouse 完全不写,只能靠与 FastenersWB 比对反推。 这正是必须保留 GPL 源作校验源的理由——它是唯一能判定另外两家统计量的标尺。

4.2 FsData 多表节(决定摄取管线的形状)

Section titled “4.2 FsData 多表节(决定摄取管线的形状)”

192 个文件中 180 个含 ≥2 个表节。iso4762def.csv 第 68 行起是第二张表 ISO4762range(Dia, Min_L, Max_L), 与主表共用 M3 这样的行键。按文件解析时后表覆盖前表,b 被污染成 30(正确值 18)。 分节解析后该文件产出 2 张表,全库 192 文件产出 400 张表。

摄取器必须以“表节”而不是“文件”为单位,并对每张表单独记录来源文件与节名。

  • 可取:BOLTS 13 个 LGPL 2.1+ 集合 + 4 个 MIT + 1 个 Unlicense;bd_warehouse 全部(Apache-2.0)。
  • 不可取进分发物:FastenersWB(GPL-2.0)。它只在离线校验中使用,产物是“是否一致”的布尔与差异清单, 不是它的数值。差异清单里若要落具体数字,取的是 BOLTS/bd_warehouse 的值,不是 FsData 的值。
  • LGPL 2.1+ 的数据随产品分发需要满足 LGPL 的分发义务(提供对应源与替换能力)。 按前一篇 §5 的结论,产品内置零件库还需要一条用户设计产物豁免,KiCad 的例外条款是唯一成熟先例。 [待验证] LGPL 数据 + 设计豁免的组合是否需要向 BOLTS 上游取得额外声明。

以 BOLTS 的本体为骨架,补上统计量轴,落成 Aira 自己的 schema:

PartFamily ← 对应 BOLTS class
id
designations[] ← 一族多标准号
body ISO | DIN | EN | GB | ASME | …
designation "ISO 4762"
status active | withdrawn
replaces "DIN912"
labeling "内六角圆柱头螺钉 %(key)s"
parameters
types symbol → Length(mm) | Length(in) | Angle(deg) | Number | Bool | String | TableIndex
free[] 自由参数(可由用户/AI 指定)
defaults 自由参数默认值
choices 每个 TableIndex 的有限论域 ← §11.2 的码本
measurements[] ← 本文新增的一轴
symbol "h"
statistic nominal | min | max | mean
quantity length | angle | count
table key → value
provenance[] ← 每个数值的来源与校验状态
source bolts:washer/plainwasher1 | bd:plain_washer_parameters.csv
crossChecked agree | differ | untested | suspect
checkedAgainst fasteners_wb:ISO7089def

suspect 是 §11 的实测结果倒逼加进来的:两个源给出相同的值不等于该值正确, 它们可能共享同一个祖先错误。agree 只能表示“两处一致”,不能表示“已确认正确”。

三点设计理由:

  • measurements 与 parameters 分开,是因为 4.1:参数是输入(自由维度 + 论域),量测是输出(带统计量的事实)。 BOLTS 把两者压在一张 tables 里,混淆了这两件事。
  • provenance.crossChecked 让 4.1 的比对结果进入数据本身而不是留在一次性报告里。 未验证的列必须显式标 untested,不能默认可信——这是本次调研自身覆盖率有限的直接后果。
  • designations[] 保留 BOLTS 的多标准共表,因此 GB/T 是加一条 designation,不是加一张表(§7)。

摄取管线四步,每步可独立重跑:

  1. 解析:BOLTS 走 YAML + !include;bd_warehouse 走 CSV;FsData 走分节解析器。
  2. 归一:符号 → (symbol, statistic);单位统一 mm;Table Index 论域抽取。
  3. 交叉核对:以 FsData 为标尺逐列比对,写回 crossChecked。差异不自动裁决,进人工清单。
  4. 发布:产出只含可分发源数值的规范表,附来源与校验状态。

cq_warehouse 的螺纹实现(thread.py)在源码注释里记录了选型过程:试过 sweep、带旋转的 extrude 等多种方案后, 最终采用由顶径螺旋线与根径螺旋线直接构造面、再缝合成实体。维护版 Replicad 的原语与这条路径逐项对应:

需要的能力 Replicad 现有导出 位置
螺旋线 makeHelix src/shapeHelpers.ts:80
线段/圆弧组装成 wire assembleWire :274
wire → face(含非平面) makeFace / makeNonPlanarFace :310 / :339
faces/shells → solid makeSolid、weldShellsAndFaces :600 / :581
正多边形(六角头/内六角) makePolygon :631
回转/拉伸/倒角/圆角 revolution 及 aira/profile-exact-* src/aira/

结论:紧固件几何(含真实螺纹)不需要新增 OCCT 绑定。 按前一篇 §4.1 的教训,默认走光圆柱, 真实螺纹是显式可选项;两条路径共用同一份参数。

7. 落点:零件是库函数,不是新 operation

Section titled “7. 落点:零件是库函数,不是新 operation”
  • program-compartment.ts:353 把 replicad 的全部非 host 导出注入 AI 程序沙箱;
  • scripts/generate-library-reference.mjs 从源码生成 library-reference-data.ts(当前 1307 条,带 upstreamCommit/sourceHash);
  • aira_library_reference 工具直接读这份数据。

所以在维护版 Replicad 里新增 iso4762(size, length, opts) 这样的函数,发现、调用、诊断三条链路全部自动接通: AI 用既有工具查到签名,程序直接调用,失败诊断走既有的 program-compartment 路径。

反过来,把零件做成新的 AMIR operation(如 part.iso4762@1.0.0)需要:operation descriptor、JSON Schema、 能力目录条目、aira.semantic-ref.* 命名算法、结果 schema 版本、证书路径——每加一个标准件族就要走一遍。 两条路的产出几何完全相同,但后者的边际成本高一个量级,且违反“不得另建平行执行器”。

边界:零件作为库函数意味着它在 AMIR 里表现为程序节点内部的调用,不是独立可寻址的实体。 若将来要做 BOM、替换、实例共享(§11.3 的 hash-consing),需要的是 assembly.compose 落地 (该 op 目前只有 spec、无实现),而不是把零件提升为 operation。

8. GB/T:模型不用改,只需加 designation

Section titled “8. GB/T:模型不用改,只需加 designation”

BOLTS 已经用“一张表服务多个标准号”表达等价关系,并带标准生命周期:

class hexbolt2 ← 一张尺寸表
ISO ISO 4014 status=active replaces=DIN931
DINENISO DINENISO 4014 status=active
DINEN DINEN 24014 status=active
class hexbolt1
DIN DIN 931 status=withdrawn

GB/T 5782 只是往 hexbolt2 再挂一条 body=GB, designation="GB/T 5782"。标注、检索、BOM 立即生效。

[待验证] 挂载的前提是逐尺寸核对 GB/T 与 ISO 的实际差值(GB/T 多为修改采用)。 在核对完成前,GB/T designation 必须带 equivalence: unverified 标记,不能直接对用户显示为等同。 同样的怀疑也适用于 BOLTS 已有的等价断言——plainwasher1 一张表同时声称是 ISO 7089、EN 7089、 DINEN 27089、DINENISO 7089 与 DIN 125 A,本次未核对这五者是否逐尺寸一致。

  • 不取 FastenersWB 的数值(GPL-2.0),只用它做离线校验。
  • 不取 cq_warehouse,已被 bd_warehouse 覆盖。
  • 不复制上游 builder:几何在维护版 Replicad 内实现,产品适配器不加纯转发层。
  • 不引入 PartCAD:其寻址/版本化职责与 AMIR + Document/Revision 重叠。
  • 不集成商业目录(TraceParts、CADENAS、3DSource),条款禁止再分发。
  • 不做 STEP 目录导入:AMIR v0.1 无 STEP import。
  1. [待验证] BOLTS 逐集合许可声明与仓库 GPL-3.0 的法律关系;LGPL 2.1+ 数据随浏览器产品分发的义务边界。
  2. [待验证] 除本文比对的 3 个标准、4 个统计量列之外,其余列的跨源一致性全部未测。
  3. [待验证] BOLTS 内部的多标准等价断言(如 ISO 7089 = DIN 125 A)未逐尺寸核对。
  4. [待验证] GB/T 与 ISO 的逐尺寸差值,需标准正文。
  5. [待验证] 浏览器 WASM 下真实螺纹的实际几何开销,需在 Aira 管线上实测。
  6. 复现方式:四个源以 git clone --depth 1 取得后,按 §2 的解析方式重跑即可再现全部计数与比对结论。 若要长期保留,按 SOURCES.lock.json 既有约定 pin 住并记录 licenseEvidence——该动作需要显式授权。

以 ISO 4762 内六角圆柱头螺钉一族打通整条路径,验证 §5–§7 的设计。落地只有两个文件:

  • third_party/maintained/replicad/src/standardParts.ts(新增;首版误放在 src/aira/,该目录以 rootDir: src/aira 单独编译并经 @aira/replicad 引主库,相对引用会打破 build:aira,已移出)
  • third_party/maintained/replicad/src/index.ts(增加一行 export * from './standardParts';)

没有新工具、没有新 operation、没有新目录、没有测试文件、没有 Gate 或证据收集器。

11.1 四列尺寸的统计量(实测,非推定)

Section titled “11.1 四列尺寸的统计量(实测,非推定)”

对 bd_warehouse socket_head_cap_parameters.csv(upstream 6d05b29e)逐列比对 FastenersWB FsData/iso4762def.csv,行键归一化(bd 用 M3-0.5,FsData 用 M3)后:

列 统计量 与 FastenersWB 比对
k 头高 公称 19/19 完全一致
t 沉孔深 最小值 19/19 完全一致
dk 头径 最大值(滚花头) 系统性大于 dk_max(光头)0.14–0.18 mm
s 内六角对边 公称扳手尺寸 系统性小于 FsData s_mean 约 0.06 mm

后两列若按符号名直接合并,就会重演 §4.1 的垫圈错误。统计量写进每个字段的 JSDoc, 经由既有的 generate-library-reference.mjs 进入 AI 可见的描述——不新建任何元数据结构。

11.2 新证据:交叉校验抓不到共同祖先错误

Section titled “11.2 新证据:交叉校验抓不到共同祖先错误”

ISO 4762 的公称长度范围,bd_warehouse 与 FastenersWB 都给出 M20 = 16–100 mm, 与 M10 的 16–100 完全相同,而 M16 是 25–160、M24 是 40–200。M20×16 在物理上不成立(头高就有 20 mm)。 两源一致但都可疑,说明它们共享同一祖先,独立性假设不成立。

因此长度域数据没有进入实现:几何不需要它,而带着一个已知可疑的范围做参数校验, 会把合法的 M20×150 判为非法。参数域校验等这份数据有可信来源之后再补。 provenance.crossChecked 因此新增 suspect 取值(见 §5)。

  • 几何正确性:20 个公制规格逐一用 OCCT 实测体积对比解析闭式解 π(dk/2)²k + π(d/2)²L − (√3/2)s²t,20/20 相对误差 0.00e+0(M8 = 1987.0263 mm³)。
  • 发现层:重新生成参考索引后条目由 1307 增至 1315, iso4762SocketHeadCapScrew(size: Iso4762Size, length: number): Shape3D 以 access: program 收录, Iso4762Size 的有限论域完整出现在签名里——§11.2 的“码本”不需要额外结构,类型本身就是。
  • 诊断:非法规格与非正长度均抛出带可选值清单的错误,走既有 program-compartment 路径。
  • 类型检查:@aira/replicad 与 apps/web 均通过;四个新符号在仓库内零命名冲突。

验证脚本是一次性的,跑完即删,未进入仓库。

真实螺纹(默认光圆柱,§6 的结论)、配合孔(clearance_hole_sizes.csv 的统计量尚未实测, 不上未验证的数据)、螺距与长度域、ASME B18.3 英制列、其余 53 个零件族、GB/T designation。 这些都在数据或需求就绪时再补,不预先搭结构。