标准件开源库整合:可二次开发的基底设计
状态: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. 结论摘要
Section titled “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+ 那一档。[实测] - BOLTS 是唯一带标准本体的源:94 个标准号,带
body/status(active/withdrawn)/replaces关系, 7 种参数类型(Length (mm)360 处、Table Index73、Length (in)16、String11、Number2、Bool1、Angle (deg)1), 支持一维与二维表,且bolttools/common.py的Parameters.union()把“参数集合合并”定义成带类型兼容检查的操作。 - bd_warehouse 是 cq_warehouse 的严格超集,同为 Apache-2.0、同一作者:48 个 CSV / 1752 行 对 34 个 / 930 行, 多出 O 形圈(349 行)、挡圈 DIN 471/472(174 行)、轴键、ISO 228-1 管螺纹等 14 个文件。cq_warehouse 可以整体弃用。
- FastenersWB 覆盖最全但许可最差:192 个文件、分节后 400 张表、7883 行,ISO 93 个文件、DIN 39、ASME 32, 许可 GPL-2.0。它是校验源,不是取用源。
- 阻塞级发现一:同名不同义。 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% 的垫圈。规范模型的合并键必须是(标准号, 符号, 统计量)。[实测] - 阻塞级发现二:FsData 一个文件多张表。 192 个文件里 180 个含 ≥2 个表节(
din103def.csv有 71 节)。 朴素按文件解析会把ISO4762def和ISO4762range混成一张表——本次首轮解析就踩中,M3 的螺纹长b从 18 变成 30。 摄取必须分节。[实测] - 几何层可移植,无需新绑定。 cq_warehouse 的源码注释记录了它试过 sweep 与 extrude-with-rotation 后
最终选择“从螺旋线直接构面”;维护版 Replicad 已经具备这条路径需要的全部原语:
makeHelix、assembleWire、makeFace/makeNonPlanarFace、makeSolid、weldShellsAndFaces、makePolygon、makeCylinder。[实测] - 发现层零改动。
third_party/maintained/replicad/scripts/generate-library-reference.mjs从源码生成 AI 可见的 API 索引(带upstreamCommit/sourceHash),程序沙箱program-compartment.ts暴露 replicad 全部非 host 导出。 往维护版 Replicad 加一个零件函数,AI 立即可发现可调用,不需要新工具、新目录、新检索执行器。 - 因此零件不应该是新的 AMIR operation,而应该是程序里的库调用。 新增 operation 要配 descriptor、能力条目、 naming algorithm、schema 版本与证书路径;库函数一样都不需要,且自动满足“不得另建平行执行器”。
- GB/T 的载体已经存在:BOLTS 用“一张表服务多个标准号”表达等价(
hexbolt2一张表同时是 ISO 4014 / DINENISO 4014 / DINEN 24014,并标replaces: DIN931,而 DIN 931 自身标status: withdrawn)。 GB/T 5782 只是往这张表再挂一个 designation,模型不用改。
2. 方法与证据边界
Section titled “2. 方法与证据边界”四个库以 git clone --depth 1 克隆到会话临时目录,用 Python 直接解析原始数据文件实测,不依赖上游文档或检索摘要。
BOLTS 的 .blt 用 yaml.SafeLoader 加自定义 !include 构造器解析(型材数据经 !include 外挂在 data/profile_*/ 下);
FsData 用分节解析器(单字段行 = 表名,其后第一行 = 表头)。
[待验证] 本文所有跨源数值比对只覆盖 ISO 4762 / 4032 / 7089 三个标准的公共列,以及统计量扫描能触及的列
(要求 FsData 同时存在公称列与 _min/_max/_mean 变体列,实际只有 4 列满足)。其余列未验证,不能推定一致。
3. 四源实测清单
Section titled “3. 四源实测清单”| 源 | 许可 | 数据规模 | 结构 | 独有价值 | 定位 |
|---|---|---|---|---|---|
| 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. 三个阻塞级发现
Section titled “4. 三个阻塞级发现”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 张表。
摄取器必须以“表节”而不是“文件”为单位,并对每张表单独记录来源文件与节名。
4.3 许可分层(决定能取什么)
Section titled “4.3 许可分层(决定能取什么)”- 可取: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 上游取得额外声明。
5. 规范数据模型
Section titled “5. 规范数据模型”以 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:ISO7089defsuspect 是 §11 的实测结果倒逼加进来的:两个源给出相同的值不等于该值正确,
它们可能共享同一个祖先错误。agree 只能表示“两处一致”,不能表示“已确认正确”。
三点设计理由:
measurements与parameters分开,是因为 4.1:参数是输入(自由维度 + 论域),量测是输出(带统计量的事实)。 BOLTS 把两者压在一张tables里,混淆了这两件事。provenance.crossChecked让 4.1 的比对结果进入数据本身而不是留在一次性报告里。 未验证的列必须显式标untested,不能默认可信——这是本次调研自身覆盖率有限的直接后果。designations[]保留 BOLTS 的多标准共表,因此 GB/T 是加一条 designation,不是加一张表(§7)。
摄取管线四步,每步可独立重跑:
- 解析:BOLTS 走 YAML +
!include;bd_warehouse 走 CSV;FsData 走分节解析器。 - 归一:符号 →
(symbol, statistic);单位统一 mm;Table Index论域抽取。 - 交叉核对:以 FsData 为标尺逐列比对,写回
crossChecked。差异不自动裁决,进人工清单。 - 发布:产出只含可分发源数值的规范表,附来源与校验状态。
6. 几何层:可移植性实测
Section titled “6. 几何层:可移植性实测”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=activeclass hexbolt1 DIN DIN 931 status=withdrawnGB/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,本次未核对这五者是否逐尺寸一致。
9. 不取清单
Section titled “9. 不取清单”- 不取 FastenersWB 的数值(GPL-2.0),只用它做离线校验。
- 不取 cq_warehouse,已被 bd_warehouse 覆盖。
- 不复制上游 builder:几何在维护版 Replicad 内实现,产品适配器不加纯转发层。
- 不引入 PartCAD:其寻址/版本化职责与 AMIR + Document/Revision 重叠。
- 不集成商业目录(TraceParts、CADENAS、3DSource),条款禁止再分发。
- 不做 STEP 目录导入:AMIR v0.1 无 STEP import。
10. 待验证与复现
Section titled “10. 待验证与复现”- [待验证] BOLTS 逐集合许可声明与仓库 GPL-3.0 的法律关系;LGPL 2.1+ 数据随浏览器产品分发的义务边界。
- [待验证] 除本文比对的 3 个标准、4 个统计量列之外,其余列的跨源一致性全部未测。
- [待验证] BOLTS 内部的多标准等价断言(如 ISO 7089 = DIN 125 A)未逐尺寸核对。
- [待验证] GB/T 与 ISO 的逐尺寸差值,需标准正文。
- [待验证] 浏览器 WASM 下真实螺纹的实际几何开销,需在 Aira 管线上实测。
- 复现方式:四个源以
git clone --depth 1取得后,按 §2 的解析方式重跑即可再现全部计数与比对结论。 若要长期保留,按SOURCES.lock.json既有约定 pin 住并记录 licenseEvidence——该动作需要显式授权。
11. 最小可行实现(已落地)
Section titled “11. 最小可行实现(已落地)”以 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)。
11.3 验证结果
Section titled “11.3 验证结果”- 几何正确性: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均通过;四个新符号在仓库内零命名冲突。
验证脚本是一次性的,跑完即删,未进入仓库。
11.4 刻意不做的部分
Section titled “11.4 刻意不做的部分”真实螺纹(默认光圆柱,§6 的结论)、配合孔(clearance_hole_sizes.csv 的统计量尚未实测,
不上未验证的数据)、螺距与长度域、ASME B18.3 英制列、其余 53 个零件族、GB/T designation。
这些都在数据或需求就绪时再补,不预先搭结构。