材质库来源与设计:工程材料与显示外观的统一身份:数据计划与首批接入
主文档与完整目录。本分篇保留原调查日期的依据与实测记录;其中的当前状态、建议和授权仅属于历史快照,不是执行队列。
10. 数据全面性与合规的执行计划
Section titled “10. 数据全面性与合规的执行计划”目标是同时成立的两句话:发布物里的每一行都能说清来源与许可,且覆盖足够真实产品使用。 两者不是取舍关系——把许可变成数据的字段,就能在同一张表里并存。
10.1 合规机制:许可是数据的一等字段,闸门在打包期
Section titled “10.1 合规机制:许可是数据的一等字段,闸门在打包期”- 规范化后的每一行携带
sourceId/license/citedSource/basis/verifiedBy, 不是整库一个许可,而是逐行可判定。 - 定义发布允许集:
public-domain、CC0-1.0、CC-BY-3.0、CC-BY-4.0。 - 转换脚本产出两张表:开发表(含只读校核源)与发布表(只含允许集)。
- 闸门是一条会失败的检查,不是治理文档:发布表生成时遇到允许集之外的
license值即非零退出, 接进现有build,不新建 Gate 命令、收据目录或报告树(AGENTS.md)。 - 署名产物由同一脚本生成:CC-BY 行按
citedSource聚合成署名段落,写入现有THIRD-PARTY-LICENSES.md流程(§6 已指出该生成器只扫依赖树,需要显式加入这一段)。
这条机制的意义:LGPL / CC-BY-SA 数据可以留在开发期做交叉核对,而永远进不了发布物, 且这一点由构建证明,不靠人记住。
10.2 “全面”的可验收定义
Section titled “10.2 “全面”的可验收定义”不追求牌号数量,追求族覆盖 + 常用牌号覆盖。参照商业 CAD 内置库规模(Fusion/Onshape 量级约 100–200 条):
| 族 | 目标条数 | 主来源 | 许可等级 |
|---|---|---|---|
| 碳钢 / 合金钢 | ~45 | MIL-HDBK-5J ch.2;EN 牌号名编码屈服值 | S |
| 不锈钢 | ~15 | MIL-HDBK-5J ch.2;NIST | S |
| 铝合金 | ~30 | MIL-HDBK-5J ch.3;FreeCAD 6061-T6 / 7075-T6 | S + A |
| 铜 / 黄铜 / 青铜 | ~20 | 族常量 + ASTM 牌号编码;physically-based 密度核对 | S |
| 钛 / 镁 / 镍基 | ~15 | MIL-HDBK-5J ch.4/5/6 | S |
| 铸铁 | ~8 | EN-GJL/GJS 牌号编码 + NIST | S |
| 工程塑料 | ~30 | FreeCAD CC-BY 9 张 + 厂商 TDS 逐条 | A |
| 弹性体 | ~8 | 厂商 TDS 逐条 | A |
| 木材 / 玻璃 / 混凝土 / 复合 | ~15 | FreeCAD CC-BY 7 张 + 公有领域 | A + S |
| 合计 | ~186 |
验收标准(可机检,不靠主观判断):
- 发布表 100% 有
density(mass派生对全库成立)。 - 金属族 ≥95% 有
YoungsModulus、PoissonRatio、YieldStrength、UltimateTensileStrength。 - 发布表 0 行落在允许集之外。
- 发布表 0 行触发 §4.3 的语义矛盾规则。
- 每行
citedSource可解析为具体文档与位置,不是“来自某数据库”。
10.3 来源分级
Section titled “10.3 来源分级”| 级 | 来源 | 许可 | 用法 |
|---|---|---|---|
| S | MIL-HDBK-5J(DoD,Distribution Statement A,US Gov work → 17 U.S.C. §105 公有领域);NIST 材料数据;physically-based-api(CC0);Wikidata(CC0) | 公有领域 / CC0 | 直接进发布表,无署名义务 |
| A | FreeCAD 21 张 CC-BY 卡(§4.1);厂商公开 TDS(逐条判定可引用性) | CC-BY-3.0/4.0 | 进发布表,必须署名 |
| B | FreeCAD 115 张 LGPL 卡、4 张 CC-BY-SA 卡;Supplemental-Materials(CC-BY-SA-4.0) | 传染性 | 只读校核源,进开发表,被 §10.1 闸门挡在发布物外 |
| C | MatWeb / ASM / Total Materia / AZoM / MakeItFrom;OrcaSlicer / PrusaSlicer 配置(AGPL-3.0) | 专有 / AGPL | 禁用,不抓取、不导入、不作校核 |
关于 MIL-HDBK-5J 的两点如实说明:
- 它给的是统计设计许用值(A/B basis),不是 MatWeb 风格的“典型值”。对 CAD 材料库这通常更合适,
但必须把
basis作为字段带上,不能与典型值混排。 - 17 U.S.C. §105 的公有领域效力在美国境内明确;美国政府在境外主张著作权的理论可能性存在。 结合 Distribution Statement A,实务上按可自由复用处理,但仍须法务确认。[待验证]
10.4 双源规则
Section titled “10.4 双源规则”发布表的每一行必须满足:
- ≥2 个独立来源,其中至少一个是 S 或 A 级,且作为
citedSource; - 数值分歧超阈值(密度 1%、模量 5%、强度 10%)→ 不发布,进
conflicts清单人工裁决; - B 级只能出现在
verifiedBy,不能出现在citedSource。
这条规则同时解决两件事:合规上让引用链干净;质量上直接拦掉 §4.3 那 6 行强度矛盾值。
10.5 两条轨道
Section titled “10.5 两条轨道”产品轨(不依赖数据全量,用 §4.1 的 21 张 CC-BY + 86 条 CC0 就能全程跑通):
| 阶段 | 产出 | 验收 |
|---|---|---|
| P0 契约与闸门 | contracts schema(含许可字段)、转换脚本、发布/开发双表、许可闸门接进 build |
闸门能对故意注入的 LGPL 行失败退出 |
| P1 身份与绑定 | materialId(class + grade)挂到 body,进 AMIR 文档 |
撤销/重做、保存重开、守恒与 patch 原子性全部保持 |
| P2 派生与校验 | ExactCadExpectation.mass,host 用 GProp 体积独立测量 |
声明错误质量的 plan 被否决 |
| P3 外观投影 | class → PBR,MaterialSlot 扩 PBR 字段,viewer 升 MeshPhysicalMaterial |
指定材料后显示随之改变,且外观不进文档 |
| P4 交换 | 3MF <basematerials>;STEP 维持名称+颜色,损失按 RFC-0005 申报 |
导回比较不新增静默丢失 |
数据轨(可与产品轨并行,产物是同一张发布表的行数增长):
| 阶段 | 产出 | 备注 |
|---|---|---|
| D0 基线 | 21 张 CC-BY + 86 条 CC0 归一入表,跑通双源规则与闸门 | 无法务依赖,可立即开始 |
| D1 金属主体 | 从 MIL-HDBK-5J 提取铝/钢/不锈钢/钛/镁/镍基 | 本计划最贵的一步:约 1700 页 PDF,表格密集且按温度/条件分栏,需人工核对而非自动抓取 |
| D2 族常量与牌号编码 | 铜合金族常量、EN/GB 牌号编码屈服值、铸铁 | 便宜,覆盖增量大 |
| D3 塑料与其余 | FreeCAD CC-BY 9 张 + 厂商 TDS 逐条补齐 | 逐条判定 TDS 可引用性 |
依赖关系只有一条:P0 必须先于 D0——没有闸门和许可字段就开始导数据,等于在制造后面要返工的债。
10.6 并行动作:请求上游重许可
Section titled “10.6 并行动作:请求上游重许可”向 FreeCAD 提出把 115 张 LGPL 材料数据卡(非代码)重许可为 CC-BY 的请求。 成本极低(一个 issue),收益是直接解锁 DIN/EN 钢与铜牌号这块 S 级来源覆盖不到的部分; 上游本身正在把新卡按 CC-BY-4.0 发布,方向一致。不阻塞任何阶段,成了就并入 A 级,不成也不影响 §10.2 的目标。
10.7 明确不做
Section titled “10.7 明确不做”- 不抓取 C 级来源,不用它们做校核。
- 不把 B 级数据“改写一下”后当作自有数据——改写不改变来源事实,
verifiedBy如实记录。 - 不做成本估算(§4.2:上游没有价格数据)。
- 不为材料库新建 Gate 命令、收据目录、治理清单或平行报告树。
- 不在本轮改 sealed WASM 绑定(STEP 物性推迟到有真实交换需求)。
10.8 开工前需要拍板的三件事
Section titled “10.8 开工前需要拍板的三件事”- 发布允许集是否就是
public-domain / CC0 / CC-BY-3.0 / CC-BY-4.0——是否接受 CC-BY 的署名义务 (代价:THIRD-PARTY-LICENSES.md增加一段材料署名)。若只接受 PD/CC0,塑料族要重做来源,覆盖会掉一档。 - D1 是否投入——MIL-HDBK-5J 的表格提取是本计划唯一的重成本项,也是金属覆盖的唯一 S 级来源。 不投入则金属只能停在族常量 + 牌号编码水平(约 40 条,够用但不“全面”)。
- A/B-basis 与典型值是否共存——共存则
basis是必填字段且 UI 要显示它;只留一种则要选定哪一种。
11. P0 执行记录(2026-09-09)
Section titled “11. P0 执行记录(2026-09-09)”P0 已完成:契约、转换产物与打包期许可闸门,并用真实数据端到端跑通。
11.1 交付
Section titled “11.1 交付”| 文件 | 职责 |
|---|---|
packages/aira-contracts/src/material-library.ts |
契约:SI 基本单位的物性行、外观行、逐行 citation 与 corroboration、扣留原因 |
packages/aira-contracts/scripts/material-library-policy.mjs |
政策与闸门的唯一实现:允许集、逐类容差、物理量程、语义校验 |
packages/aira-contracts/scripts/generate-material-library.mjs |
读 fixtures、过闸门、生成发布表与署名清单 |
packages/aira-contracts/fixtures/materials/ |
种子数据:CC0 外观 11 条、CC-BY 物性 10 条 |
packages/aira-contracts/src/generated/material-library-data.ts |
生成物(14 KB):发布表 + 闸门实际使用的政策常量 + MATERIAL_LIBRARY_ATTRIBUTIONS |
闸门挂在 generate.mjs 内,而 generate 是 @aira/contracts 的 build 第一步——
任何一次构建都不可能产出未过闸门的表,不需要额外的 Gate 命令或收据目录。
署名清单由决定“这行能发”的同一步生成,不另行手工维护。
11.2 闸门验收
Section titled “11.2 闸门验收”注入一行 LGPL-2.0-or-later 的合成材料后运行构建:
Error: The material library gate rejected 1 row(s): material metal.steel.gate-probe: licence "LGPL-2.0-or-later" may not ship. Publishable licences are public-domain, CC0-1.0, CC-BY-3.0, CC-BY-4.0; a source under any other terms may corroborate a value under verifiedBy, where only the agreement is recorded.退出码 1,构建中止。移除该行后恢复正常,探针未留在仓库中。
本批验证:contracts 生成、tsc -p tsconfig.build.json、apps/web typecheck、
eslint(--max-warnings 0)与 prettier 全部通过。
11.3 种子结果:发布 5 行,扣留 4 行
Section titled “11.3 种子结果:发布 5 行,扣留 4 行”| 结果 | 材料 | 说明 |
|---|---|---|
| 发布 | metal.steel.generic、polymer.pc.generic、polymer.pet.generic、polymer.pp.generic、polymer.pmma.generic |
密度经 CC0 源交叉核对,其余属性逐条声明为单源 |
扣留 source-disagreement |
polymer.pvc.generic |
密度 1380 vs CC0 源 1300,差 6.15% 超 generic 容差 5%(增塑与硬质 PVC 的真实差异) |
扣留 no-corroboration |
metal.aluminum.6061-t6 |
CC0 源的 Aluminum 是纯元素,不能给一个牌号做同精度核对;grade 级第二来源等 D1 |
扣留 unknown-appearance-class + no-corroboration |
polymer.pla/pa6/ptfe.generic |
CC0 外观库没有对应条目 |
四种扣留路径都由真实数据触发,不是构造出来的示例。
11.4 对已批准计划的两处调整(附理由)
Section titled “11.4 对已批准计划的两处调整(附理由)”- §10.4 的容差按 specificity 分档,不再是单一的 1%/5%/10%。 证据:CC-BY 与 CC0 两个诚实来源在通用塑料密度上的实测差为 0–6.15% (PC 0%、PET 0%、PMMA 1.69%、PP 1.78%、PVC 6.15%)。通用行按定义是族代表,两个来源合法地 选了不同代表;用 1% 卡它只会否掉“作为通用值正确”的数值,而不是抓出错误。 牌号行保持 1%/5%/10% 不变,因为牌号指的是同一个确定的东西。密度在两档里都是最严的一档。
strengthBasis增加unstated。FreeCAD 通用卡不声明基准;把它记成typical是我替来源 做断言。unstated是诚实答案,并且明确不可作为设计许用值。
11.5 种子中被刻意丢弃的属性
Section titled “11.5 种子中被刻意丢弃的属性”规范化不是搬运。以下值有来源但没有进表,理由逐条记录在 fixture 的 note 里:
- 4 处
YieldStrength > UltimateTensileStrength(PC、PET、PMMA、PLA):丢弃 yield。 对塑料这可能是“屈服应力 vs 断裂应力”的语义差异,但消费方无从判断来源指哪一个, 当作许用上界用就是错的。 - PET 的
ShearModulus0.0385 GPa:与该卡自身的 E=3150 MPa、ν=0.36 推出的 ≈1.16 GPa 差 30 倍,丢弃。 - PP 的强度对(UTS 79.7 MPa、yield 32.8 MPa):顺序虽然合法,但 79.7 MPa 超出聚丙烯的族范围, 两个值都丢弃。闸门只能查顺序,查不出标签互换——这是当前规则的已知边界,需要 D3 的第二来源解决。
11.6 P0 不包含
Section titled “11.6 P0 不包含”材料尚未挂到 body、未进 AMIR 文档、未参与撤销/重做与守恒(P1);没有 expect.mass(P2);
viewer 仍是 MeshStandardMaterial,未消费外观表(P3);未新增 AI 检索工具;未改 3MF 与 sealed WASM。
12. D0 与 P1 执行记录(2026-09-09)
Section titled “12. D0 与 P1 执行记录(2026-09-09)”12.1 D0:基线导入
Section titled “12.1 D0:基线导入”新增 scripts/import-material-sources.mjs:手工运行、不进构建,
读取 materialize 后的参考克隆,产出已审阅的 fixtures。单位换算、佐证偏差、被丢弃的属性全部由脚本推导,
fixtures 里没有一个手敲的数字。许可过滤出现两次且共用同一个 MATERIAL_PUBLISH_LICENSES:
导入期决定值不值得写下来,闸门期决定能不能发——一份政策,两个执行点。
两个来源已按仓库既有机制固定到
SOURCES.lock.json:
FreeCAD 82c7a09b(140 张标准卡,逐卡许可与 §4.1 实测一致)、
physically-based-api eb4408aa(deploy/materials.json,86 条,CC0-1.0)。
结果:外观类 43 条、物性行导入 20 条、发布 14 行、扣留 6 个材料共 11 条原因。
| 结果 | 材料 |
|---|---|
| 发布(14) | 6061-T6、7075-T6、steel.generic、steel.calculix、钢筋 B500、混凝土通用与 EN C35/45、玻璃通用与 E/S-2 玻纤、PC、PET、PMMA、PP |
扣留 source-disagreement(1) |
PVC(密度差 6.15%,增塑与硬质 PVC 的真实差异) |
扣留 unknown-appearance-class(5) |
木材、ABS、PA6、PLA、PTFE——CC0 外观库没有这些条目 |
扣留 no-corroboration(5) |
与上面 5 条同一批:它们同时缺第二来源 |
当前唯一的结构性缺口是外观,不是物性:5 个材料的物性都齐备且许可干净,只是没有可发布的外观类。 补齐需要一个 PD/CC0 的聚合物与木材外观来源,或者接受一个通用介电类(本文不采用后者,因为那等于编造数值)。
导入期自动丢弃的属性(日志逐条给出理由):
- ABS、PMMA、PC、PET、PLA 的
YieldStrength高于同卡的抗拉强度 → 丢弃 yield。 - PET 的
ShearModulus只有该卡 E 与 ν 推出的各向同性值的 0.033 倍 → 丢弃。 - PP 的强度对由显式覆盖丢弃(抗拉 79.7 MPa 超出聚丙烯族范围),理由写在脚本里而不是藏在规则里。
12.2 本批的两处政策调整(附证据)
Section titled “12.2 本批的两处政策调整(附证据)”- 线性颜色分量上界从 1 放宽到 2。 金的红通道实测 1.059、铯的高光 1.073——超出 sRGB 色域的 反射率是真实测量值,不是错误。渲染时钳制是显示行为;在库里钳制等于丢掉测量。
- 佐证条目必须声明自己的
specificity,容差取两者中较钝的一侧。 证据:混凝土 C35/45(4.17%)、E 玻纤(3.2%)、S-2 玻纤(1.6%)此前按 grade 的 1% 被否, 但它们的对照来源是通用参考——拿通用参考去卡牌号精度,否掉的不是错误而是“两个来源能达到的最接近”。 这条同时让 6061/7075 可以被通用铝参考佐证并发布,代价是要如实说明: 通用对照能抓住单位错误和用错材料,抓不住用错牌号;牌号级佐证等 D1。
12.3 P1:材料绑定进 AMIR 文档
Section titled “12.3 P1:材料绑定进 AMIR 文档”| 文件 | 职责 |
|---|---|
packages/aira-contracts/src/material-binding.ts |
Body.extensions['aira.material/0.1'] 的读写、别名解析、外观投影入口 |
apps/web/src/authoring/exact-body-material-v0.4.ts |
构造单条 body.put 补丁;未知 body、未解析材料、无变化三种情况直接拒绝 |
没有改 AMIR schema,也没有新增执行管线。 Body.extensions 是既有开放字段,body.put 是既有补丁操作,
model.proposePatch 是既有 Interface 操作——所以撤销/重做、保存重开、原子提交与守恒不是这批新写的,
而是这条补丁走既有 proposePatch → preview → validate → commit 路径自然继承的。新增的只是
“怎么把材料正确地放进一条 body.put,以及什么情况下拒绝”。
赋material 会触发一次几何重算(文档变了,head 前移,render packet 重新派生)。为省这次重算另建一条 提交路径会违反“不另建执行管线”,因此不做。
验证(scratch 脚本,未入库):14 行全部有密度且有可解析外观类;别名解析覆盖 id、标准号、
中英文别名与大小写空格差异;被扣留的材料不可解析(polymer.pvc.generic 查不到,因此不可能被赋到 body 上);
withBodyMaterial 不改动入参、保留其他扩展与 authority、清除时删键而非置 null;
JSON 往返后仍可读出;扩展被写坏时读作“无材料”而不是抛错。
tsc(contracts + web)、eslint(--max-warnings 0)、prettier 全部通过。
12.4 P1 未做的部分与原因
Section titled “12.4 P1 未做的部分与原因”控制器与 UI 接线没有做。 LiveWorkbenchController.ts、i18n/locales/en.ts、zh-CN.ts
当前正被并发会话修改,在这三个文件上动手会和对方的在途改动纠缠。
这部分本来也更适合放进 P3:材料能设却看不见,不是一个可交付的产品状态。
P3 会同时补上外观投影和选择控件,那时接线是纯 UI 改动。
13. P2 与 P3 执行记录(2026-09-09)
Section titled “13. P2 与 P3 执行记录(2026-09-09)”13.1 P2:expect.massKg 与 set-material
Section titled “13.1 P2:expect.massKg 与 set-material”expect 增加 massKg(千克)。host 用已有的体积测量乘以材料密度得到质量,
与 volume 共用 quantityRelative 容差。没有新增任何几何测量。
ExactCadPlanStep 增加 set-material:像 replace-program 不指名程序节点一样,它不指名 body,
由 host 解析文档中唯一的 body;材料可写 id、标准号或常用名,解析不到直接拒绝。
该步骤直接复用 P1 的 createExactBodyMaterialPatchV04——P1 的补丁构造器由此拿到了它的调用方。
set-material 可以带 expect,并且是 massKg 第一个能被满足的步骤:赋材料与断言质量是同一步,
不需要先赋材料再补一个借口性的编辑。它以 affects: []、enforce: true 进入守恒检查——
材料赋值不该改变任何几何,强制这一点正是 host 证明它没改的方式。
在没有材料时声明 massKg,得到的不是“未知”,而是指名缺失那一半的诊断:
measured: unknown (the output body carries no material)。
三个刻意的取舍:
- 单位写进字段名(
massKg)。毫米由文档强制,千克与克不是;名字是最便宜的一道防线。 preserve不扩展到质量。材料不变时质量守恒等价于体积守恒,而程序步骤改不了材料。- 质量的容差沿用 volume 的
quantityRelative:密度是表中一个确定的数,质量与体积严格成正比。
13.2 P3:外观投影
Section titled “13.2 P3:外观投影”| 改动 | 说明 |
|---|---|
MaterialSlot.baseColorSrgb → baseColorLinear |
改名是纠错:three.js 的 new Color(r,g,b) 按工作色彩空间(线性)解释,这个字段一直存的就是线性值,名字在说谎。上界同时放宽到 2(见 §12.2) |
MaterialSlot 增加可选 materialId / metalness / roughness |
带 materialId 的槽位是“这个零件是什么做的”,不带的是显示默认值 |
materialSlotAppearance() |
class → 槽位,并施加 AS_MACHINED_ROUGHNESS = 0.35 |
createExactFeatureRenderTransfer(..., materialId?) |
由 session 用 nodeOutputMaterialId(document, outputNodeId) 传入 |
| viewer | 消费 slot.metalness/slot.roughness;无材料时仍是原来的 0.05/0.72 |
applyMaterialPalette |
不再覆盖带材料的网格——调色板是“问题没被回答”时的外观,不是盖住答案的装饰 |
两处需要说法的选择:
- 没有升到
MeshPhysicalMaterial。ior只在透射/清漆下才看得出来,我们两者都不用; 基色、金属度、粗糙度已经是钢和 PC 在屏幕上的全部差别,MeshStandardMaterial更便宜。 这推翻了 §10.5 里 P3 的原写法,理由如上。 AS_MACHINED_ROUGHNESS = 0.35是产品选择,不是测量值,并在代码里如此标注。 库里的粗糙度测的是抛光样品,直接用会把每个金属零件画成镜子;这一个数暂代逐零件表面处理, 取值使金属度而不是光泽成为金属与聚合物的视觉分界。
13.3 验证
Section titled “13.3 验证”tsc(contracts build + web)、eslint --max-warnings 0、prettier 全过。scratch 脚本(未入库)覆盖:
set-material的语法(id / 标准号 / 中文别名可用;缺material拒绝;写bodyId拒绝——计划永远不指名 body);massKg的算术文法(100*80*10*2700/1000000000可用,科学计数法不在文法内,负值拒绝);- 质量换算:80 cm³ 的 6061(2700 kg/m³)= 0.216 kg,与声明一致;
- 外观投影:14 行全部有槽位,粗糙度都不低于 as-machined 下限,钢
metalness=1、PCmetalness=0、 两者基色不同;被扣留的材料投不出外观;返回的颜色是副本,改它不会改到库。
没有做可视验证:那需要起 dev server 并走一次真实模型调用,两者都要显式授权。
13.4 P3 未做的部分
Section titled “13.4 P3 未做的部分”人工材料选择控件没有做。 它是一个独立的交互面(view model + shell + i18n + controller),
其中两个文件正被并发会话修改;而且赋材料现在已经有了主路径——AI 计划的 set-material,
所以外观投影不是没有驱动方的死代码。控件是下一步,接线点已经就位。