feat: add offline Qt6 naming prerequisites and boundary gates
Some checks failed
real-verification / chrome (push) Has been cancelled
real-verification / freecad-oracle (push) Has been cancelled
real-verification / wasm (push) Has been cancelled

This commit is contained in:
2026-08-12 08:17:44 -04:00
parent ca6fe46030
commit 58c0807219
22 changed files with 392 additions and 9 deletions

View File

@@ -82,7 +82,7 @@
"javascript": "native/occt-history/dist/bitbybit-occt-history.js",
"wasm": "native/occt-history/dist/bitbybit-occt-history.wasm",
"javascriptSha256": "78f1cdd17a6a7b61ff8435c0ff8c912a43c4517e6ef49f3f741521662a903557",
"wasmSha256": "b6cb6307399b188cdf1377e9294b4af8e36b21783693101db8f985e41cff5fbe"
"wasmSha256": "b52125bd2c4999f62d435f0a34664556b7f1feb23590ddc0503fc6d3c7f1c8d6"
},
"protocol": "native result and history records stay inside the provider; cross-WASM handles are forbidden; STEP text is the explicit transport boundary",
"historyProtocol": {
@@ -102,6 +102,7 @@
},
"freecadNamingBuild": {
"status": "contract-only",
"prerequisiteStatus": "qt6-wasm-core-and-locked-mapped-name-source-probe-pass",
"sdkEnvironment": "FREECAD_WASM_SDK_DIR",
"requiredManifest": "manifest.json",
"requiredCallbacks": ["freecadNamingAbiVersion", "freecadNamingCapabilitiesJson", "freecadNamingEvidenceJson"],
@@ -109,6 +110,10 @@
"requiredSourceCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
"requiredEmscriptenVersion": "3.1.69",
"buildCommand": "./npmw run build:freecad-naming-worker",
"qtCoreBuildCommand": "./npmw run build:qt6-wasm-core",
"sourceProbeBuildCommand": "./npmw run build:freecad-naming-source-probe",
"sourceProbeTestCommand": "./npmw run test:freecad-naming-source-probe",
"boundaryCheckCommand": "./npmw run check:freecad-private-naming-boundary",
"checkCommand": "./npmw run check:freecad-naming-sdk",
"statusBoundary": "Missing SDK or callback probe keeps EX-TSN-02=in_progress and systemExact=false"
},

View File

@@ -32,7 +32,7 @@
{ "id": "EX-KER-01", "title": "Match OCCT construction, validation, tolerances and failure diagnostics", "priority": "P0", "status": "in_progress", "dependencies": ["EX-ORA-02"], "deliverables": ["Per-operation native differential", "Tolerance and placement contract", "Failure-code map"], "acceptance": ["Shape validity, topology, mass properties and diagnostics match locked FreeCAD fixtures", "Worker ownership returns to zero after every case"], "evidence": ["check:browser-occt", "check:chrome-geometry-features"], "exactBlockedBy": ["Not all FreeCAD builder flags and failure branches are represented"] },
{ "id": "EX-TSN-00", "title": "Fail closed when native naming or builder evidence is absent", "priority": "P0", "status": "completed", "dependencies": [], "deliverables": ["Runtime naming evidence contract", "final-shape-only and ambiguous persistence", "ElementMap2 writer evidence guard"], "acceptance": ["Final geometry cannot mint a private FreeCAD token", "Unproven stage relations and isomorphic sources cannot become stable"], "evidence": ["check:freecad-native-naming-evidence", "check:freecad-exact-history-elementmap-gate"], "exactBlockedBy": [] },
{ "id": "EX-TSN-01", "title": "Capture native stage Shape and Generated/Modified/Deleted for every builder", "priority": "P0", "status": "completed", "dependencies": ["EX-KER-01", "EX-TSN-00"], "deliverables": ["All builder-stage captures", "Multi-input and one-to-many lineage", "Local feature recompute history"], "acceptance": ["Every feature result relation has a producing native stage", "No final-result index is applied to an intermediate Shape"], "evidence": ["check:freecad-composite-history-elementmap", "check:freecad-tsn-stage-evidence"], "exactBlockedBy": [] },
{ "id": "EX-TSN-02", "title": "Expose native MappedNameRef and StringHasher decisions for every feature", "priority": "P0", "status": "in_progress", "dependencies": ["EX-TSN-01"], "deliverables": ["Native naming callback ABI", "Per-stage StringHasher evidence", "Lossless ElementMap2 token generation"], "acceptance": ["All new tokens originate in native evidence", "FreeCAD round-trip names remain byte and semantic stable"], "evidence": ["check:freecad-native-naming-evidence", "check:freecad-sketcher-partdesign-abi", "check:freecad-naming-sdk", "check:occt-history-artifact"], "exactBlockedBy": ["The shipped Worker does not link the FreeCAD private naming implementation for every builder"] },
{ "id": "EX-TSN-02", "title": "Expose native MappedNameRef and StringHasher decisions for every feature", "priority": "P0", "status": "in_progress", "dependencies": ["EX-TSN-01"], "deliverables": ["Native naming callback ABI", "Per-stage StringHasher evidence", "Lossless ElementMap2 token generation"], "acceptance": ["All new tokens originate in native evidence", "FreeCAD round-trip names remain byte and semantic stable"], "evidence": ["check:freecad-native-naming-evidence", "check:freecad-sketcher-partdesign-abi", "check:freecad-naming-sdk", "check:freecad-private-naming-boundary", "check:occt-history-artifact"], "exactBlockedBy": ["The shipped Worker does not link the FreeCAD private naming implementation for every builder"] },
{ "id": "EX-TSN-03", "title": "Resolve isomorphic topology only from unique native provenance", "priority": "P0", "status": "in_progress", "dependencies": ["EX-TSN-01", "EX-TSN-02"], "deliverables": ["Symmetric Boolean corpus", "Candidate provenance graph", "Ambiguity repair lifecycle"], "acceptance": ["Unique native sources resolve deterministically", "Non-unique sources remain ambiguous across save, undo and recompute"], "evidence": ["test:topology-replay", "check:freecad-exact-history-elementmap-gate"], "exactBlockedBy": ["Symmetric cases without unique native provenance remain intentionally ambiguous"] },
{ "id": "EX-TSN-04", "title": "Close topology naming across all feature edits and FCStd round-trips", "priority": "P0", "status": "pending", "dependencies": ["EX-TSN-02", "EX-TSN-03"], "deliverables": ["Cross-feature mutation matrix", "ElementMap2 history migration", "Long-chain LinkSub stability report"], "acceptance": ["Wrong bindings, unexplained relations and name drift are zero for the exhaustive corpus"], "evidence": ["check:freecad-fcstd-roundtrip", "check:freecad-exact-history-elementmap-gate"], "exactBlockedBy": ["Exhaustive cross-feature naming corpus is incomplete"] }
]

View File

@@ -18,7 +18,7 @@
"version": "8.0.0",
"sourceCommit": "bb75017e915f6509a4bfa8b551f853352754c2da",
"javascriptSha256": "78f1cdd17a6a7b61ff8435c0ff8c912a43c4517e6ef49f3f741521662a903557",
"wasmSha256": "b6cb6307399b188cdf1377e9294b4af8e36b21783693101db8f985e41cff5fbe"
"wasmSha256": "b52125bd2c4999f62d435f0a34664556b7f1feb23590ddc0503fc6d3c7f1c8d6"
},
"golden": {
"manifestScenarioCount": 100,

View File

@@ -139,6 +139,34 @@
"libraryPath": "build-caches/occt-history-build.tar.zst",
"required": false
},
{
"id": "qt6-wasm-core-downloads",
"source": ".cache/toolchains/qt6/downloads",
"restore": ".cache/toolchains/qt6/downloads",
"libraryPath": "sources/qtbase-6.8.2-downloads.tar.zst",
"required": true
},
{
"id": "qt6-wasm-core-source",
"source": ".cache/toolchains/qt6/src",
"restore": ".cache/toolchains/qt6/src",
"libraryPath": "sources/qtbase-6.8.2-source.tar.zst",
"required": true
},
{
"id": "qt6-wasm-core-sdk",
"source": ".cache/toolchains/qt6/install-wasm",
"restore": ".cache/toolchains/qt6/install-wasm",
"libraryPath": "toolchains/qt6-wasm-core-6.8.2.tar.zst",
"required": true
},
{
"id": "qt6-wasm-core-build",
"source": ".cache/toolchains/qt6/build-wasm",
"restore": ".cache/toolchains/qt6/build-wasm",
"libraryPath": "build-caches/qt6-wasm-core-build.tar.zst",
"required": false
},
{
"id": "opencamlib-build",
"source": ".cache/opencamlib-wasm",

View File

@@ -344,8 +344,8 @@
},
{
"path": "native/occt-history/bitbybit-occt-history.wasm",
"bytes": 23091777,
"sha256": "b6cb6307399b188cdf1377e9294b4af8e36b21783693101db8f985e41cff5fbe"
"bytes": 23091986,
"sha256": "b52125bd2c4999f62d435f0a34664556b7f1feb23590ddc0503fc6d3c7f1c8d6"
},
{
"path": "native/occt-history/browser-harness-worker.js",
@@ -402,7 +402,7 @@
"status": "signed",
"algorithm": "Ed25519",
"keyId": "bitbybit-local-release-2026",
"payloadSha256": "20fb0fbc84390befc6fa22358b25cc139fb9dde8829643b5fc4ab3e804c44181",
"signature": "QyhRB17NFPFu9Nda1rU2KW+Lv5yROFM9Lo0vY9hOexecfwzb3PWw+XWHymLc1/hYjBm3Hw7dPdQ8Ou2KapWmBg=="
"payloadSha256": "c8734e374954b614941eb295623252af2094e9de7e415a46a399936d1cc391a9",
"signature": "vtnNIPTf3sCXN2F0c5lRVO7E76DXuolr+B5dZ8YQ34rWeWbJvgLqFVIqQ3IHke9nQVUhwYOR7SR2EyG3gucBAQ=="
}
}

View File

@@ -1785,3 +1785,11 @@ Sketcher 数据模型和 FCStd codec 已覆盖 FreeCAD 1.1.1 的完整原生几
新增 `FreeCADPrivateNamingABI v1`:三项 Embind 回调分别报告 ABI version、锁定 FreeCAD 1.1.1/commit/operation 能力,并按 JSON 请求返回命名证据。Direct provider 与 Worker 都传输输入 STEP、最终 STEP/BRep、stage DAG 和 OCCT history回包必须包含原生/歧义状态、MappedNameRef、StringHasher、ElementMap2并通过 stage/result 上下文、16/32 MiB 上限、StringID、ElementMap2 和两者引用闭包检查。缺回调、版本/提交不符、operation 未声明或证据不合法均不生成 token继续保留 `final-shape-only`
`config/freecad-sketcher-partdesign-abi-contract.json``check:freecad-sketcher-partdesign-abi` 已进入默认 Sketcher 门禁Facade 为 `190/190`独立合同门、Facade boundary、锁定 FreeCAD 原生 FCStd 门和全量 `verify` 均通过。这里完成的是支持范围内的参数合同、FCStd 表面和私有 ABI/传输/验证层;当前随附的 `native/occt-history` 仍未链接 FreeCAD 私有 C++,所以浏览器实时命名实现仍为 `not-linked``EX-TSN-02``pending` 转为 `in_progress`,机器计划为 `2 completed / 37 in_progress / 13 pending / 0 blocked``systemExact=false` 和 promotion fail-closed 状态不变。
## 230. 2026-08-12 Qt6 wasm 前置条件、FreeCAD 私有源码探针与边界门
QtBase 6.8.2 源码包已通过 USTC 国内镜像取得,并用 Qt 发布包官方 SHA-256 `012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05` 校验。新增 `build:qt6-wasm-core`,固定 Emscripten 3.1.69,构建静态 wasm32 `Qt6Core`、bundled Pcre2 和 zlib离线模式只使用本机缓存缺少已校验源码包时立即失败。源码包、展开源码、可用 SDK 和可选增量构建目录均已纳入项目离线资源清单。
新增的 `build:freecad-naming-source-probe` 并未假装提供生产命名实现。它固定 FreeCAD 1.1.1 提交 `0108fd4b4850cc46e625b60e53cea7a7bbe69f8d`,同时校验 `IndexedName.cpp``MappedName.cpp` 的逐文件 SHA-256再把这两个原始编译单元与 wasm Qt6Core 编译为独立探针。运行时验证 IndexedName 解析、MappedName 追加和 tag 读取;探针明确检查不导出 `freecadNamingAbiVersion``freecadNamingCapabilitiesJson``freecadNamingEvidenceJson`。这证明的是锁定基础源码与工具链可交叉编译,不包含完整 StringHasher、FreeCADApp/Part 静态库或生产 Worker bridge。
新增 `check:freecad-private-naming-boundary`,跨 ABI 合同、兼容性矩阵和 exact 计划校验同一状态,并接入默认 `verify`、真实 wasm lane 和离线 smoke。准确边界保持不变随附 OCCT Worker 仍没有链接 FreeCAD 私有 C++ 命名实现,制品仍无三项私有命名回调;`shippedWorkerImplementation=not-linked``freecadNamingBuild.status=contract-only``EX-TSN-02=in_progress``systemExact=false`。本批只完成可离线复现的前置构建和防止状态误提升的机器门禁。

View File

@@ -393,6 +393,10 @@ PartDesign Mirrored 已形成 experimental whole-shape 垂直切片Facade 验
ABI 输入现同时携带文档 `objectId`、FCStd 原生正整数 object tag、上一阶段命名证据、明确的 result object/tag 和阶段 DAGobject tag 会从 `Document.xml``Object.id` 导入,按稳定值写回 FCStd并通过 SQLite schema v7、OPFS 重开和 checkpoint 往返。`build:freecad-naming-worker` 是独立的 fail-closed 构建入口只接受锁定提交、Emscripten 3.1.69、wasm Qt/Python、FreeCADBase/FreeCADApp/Part 静态库及三回调 bridge 的哈希清单;普通 `build:occt-history` 继续是 OCCT-only。`check:occt-history-artifact` 会实际实例化 WASM 并探测三回调,当前结果为 unavailable因此 `EX-TSN-02=in_progress``systemExact=false` 保持不变。
Qt 前置条件已按独立、可离线复现的链路落地:`build:qt6-wasm-core` 使用 Emscripten 3.1.69 构建 QtBase 6.8.2 静态 wasm `Qt6Core`,下载使用 USTC 国内镜像,但必须先通过 Qt 发布包官方 SHA-256离线模式缺包时直接失败不允许回退联网。`build:freecad-naming-source-probe` 进一步锁定 FreeCAD 提交及 `IndexedName.cpp``MappedName.cpp` 两个原始编译单元的内容哈希,并验证它们能与 wasm Qt6Core 一起生成和执行 wasm32 探针。该探针使用最小编译适配头,不包含完整 `StringHasher`、FreeCADApp/Part 静态库或生产 bridge也明确禁止导出三项生产命名回调因此只消除工具链和基础源码可编译性风险不构成 `FreeCADPrivateNamingABI` 的生产实现。
`check:freecad-private-naming-boundary` 同时读取 ABI 合同、兼容性矩阵和 exact 计划,固定校验 `shippedWorkerImplementation=not-linked``freecadNamingBuild.status=contract-only``EX-TSN-02=in_progress``systemExact=false`;该检查已进入默认 `verify`、真实 wasm lane 和离线 smoke。只有生产 OCCT Worker 实际链接锁定的 FreeCAD 私有静态库/bridge且制品探针取得三项回调和完整命名证据后才能在后续批次修改这些状态。
Sketcher/PartDesign 的 Web 支持范围新增可执行参数合同Sketcher 覆盖 FreeCAD 1.1.1 FCStd 表面的 9 类 geometry、19 类 constraint 和 10 类 InternalAlignment 语义PartDesign 覆盖 Facade 已支持的 21 个 family、202 个属性槽和 72 个语义分区,并在对象创建及属性编辑时执行跨字段校验。`check:freecad-sketcher-partdesign-abi` 会从实现重算这些计数并拒绝陈旧报告;该“完整”限定于 supported Web Facade不包含尚未实现的 FreeCAD PartDesign TypeId也不表示 basic TypeScript solver 已求解全部圆锥曲线约束。
逐 feature 等级目前由 `config/compatibility-matrix.json``facadeCapabilities.geometry.featureLevels` 管理Pad/Pocket/Revolution/Groove/Boolean 为有 native history 子集的 `compatible`Fillet/Chamfer/MultiTransform 保持 `experimental``systemExactEvaluation.exact` 必须在所有 feature 的阶段 Shape/history、私有 token 证据和同构来源都闭合后才允许改为 true当前值固定为 false阻断项为私有 FreeCAD token 算法、没有原生 builder stage、以及无唯一同构来源。

View File

@@ -16,6 +16,7 @@
- FreeCAD 1.1.1(含 GSL、OndselSolver、AddonManager、测试子模块、bitbybit、OCCT 8、OpenCAMLib、CAMotics/C! 和 LinuxCNC Web 工作树;
- FreeCAD headless/desktop Oracle、FreeCAD sysroot、OCCT/PlaneGCS 原生 Worker 制品和可选增量构建目录;
- Playwright Chromium/Firefox/WebKit、Boost/Eigen 头文件,以及本机 `/var/cache/apt/archives` 中的 Debian 安装包池。
- QtBase 6.8.2 源码、静态 wasm Qt6Core SDK 与可选增量构建缓存;源码包使用 Qt 官方 SHA-256 校验,国内 USTC 镜像仅作为传输源。
LinuxCNC 和 CAMotics 存在尚未合入各自上游提交的本地适配,因此保存完整工作树快照。`working_ocl/` 是上述源码的历史重复副本,不作为规范资源;构建入口实际使用的 `OpenCAMLib/``CAMotics/``.cache/bitbybit/bitbybit` 才进入资源库。

View File

@@ -0,0 +1,34 @@
#include <emscripten/bind.h>
#include <App/IndexedName.h>
#include <App/MappedName.h>
#include <stdexcept>
#include <string>
namespace
{
std::string freecadPrivateNamingSourceProbe()
{
const Data::IndexedName indexed("Edge12");
if (!indexed || indexed.getIndex() != 12 || std::string(indexed.getType()) != "Edge") {
throw std::runtime_error("FreeCAD IndexedName source probe failed");
}
Data::MappedName name(indexed);
name += ";:M;CUT;:H2a:7,E";
long tag = 0;
int length = 0;
char type = 0;
const int position = name.findTagInElementName(&tag, &length, nullptr, &type);
if (position < 0 || tag != 0x2a || type != 'E') {
throw std::runtime_error("FreeCAD MappedName source probe failed");
}
return name.toString();
}
} // namespace
EMSCRIPTEN_BINDINGS(freecad_private_naming_source_probe)
{
emscripten::function("freecadPrivateNamingSourceProbe", &freecadPrivateNamingSourceProbe);
}

View File

@@ -0,0 +1,27 @@
#pragma once
#define APP_STRING_ID_H
#include <QByteArray>
namespace App
{
class StringIDRef
{
public:
void toBytes(QByteArray& bytes) const
{
bytes.clear();
}
bool operator<(const StringIDRef&) const
{
return false;
}
bool operator==(const StringIDRef&) const
{
return true;
}
};
} // namespace App

View File

@@ -0,0 +1,3 @@
#pragma once
#define FC_LOG_LEVEL_INIT(...)

View File

@@ -0,0 +1,3 @@
#pragma once
#define HAVE_Q_DISABLE_COPY_MOVE

View File

@@ -0,0 +1,16 @@
import createProbe from './dist/freecad-private-naming-source-probe.js'
const probe = await createProbe()
const result = probe.freecadPrivateNamingSourceProbe()
if (result !== 'Edge12;:M;CUT;:H2a:7,E') throw new Error(`Unexpected FreeCAD private naming source probe result: ${result}`)
for (const forbidden of ['freecadNamingAbiVersion', 'freecadNamingCapabilitiesJson', 'freecadNamingEvidenceJson']) {
if (typeof probe[forbidden] === 'function') throw new Error(`Source prerequisite probe must not export production ABI callback ${forbidden}.`)
}
console.log(JSON.stringify({
status: 'source-prerequisite-pass',
freecadVersion: '1.1.1',
sourceCommit: '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d',
linkedSources: ['App/IndexedName.cpp', 'App/MappedName.cpp'],
result,
productionWorkerLinked: false,
}, null, 2))

View File

@@ -43,6 +43,21 @@ publishing the OCCT-only artifact. A successful artifact probe still only
establishes ABI linkage; exact promotion additionally requires valid
MappedNameRef, StringHasher, ElementMap2, stage history, and round-trip evidence.
The repository also carries a prerequisite-only source probe. It builds QtBase
6.8.2 `Qt6Core` for wasm, then compiles the locked FreeCAD `IndexedName.cpp` and
`MappedName.cpp` sources without exporting the production naming callbacks:
```bash
./npmw run build:qt6-wasm-core
./npmw run build:freecad-naming-source-probe
./npmw run test:freecad-naming-source-probe
./npmw run check:freecad-private-naming-boundary
```
Passing this probe establishes that the private source subset and toolchain are
cross-compilable. It does not link the production OCCT Worker, does not close
EX-TSN-02, and does not change `systemExact=false`.
The versioned JSON request carries document `objectId`, stable positive
`objectTag`, prior naming evidence, result object identity, result tag, stage
DAG, STEP/BRep, and OCCT Generated/Modified/Deleted history. No Web fallback is

View File

@@ -49,6 +49,7 @@
"test:golden:freecad:family-failures": "node scripts/run-freecad-golden-failures.mjs --manifest=fixtures/freecad-golden/feature-families/failures/manifest.json",
"check:occt-history-artifact": "node scripts/check-occt-history-browser-artifact.mjs",
"check:freecad-naming-sdk": "node scripts/check-freecad-naming-sdk.mjs",
"check:freecad-private-naming-boundary": "node scripts/check-freecad-private-naming-boundary.mjs",
"test:browser-occt": "node scripts/run-browser-occt-harness.mjs",
"test:freecad:threeway": "node scripts/run-freecad-threeway-boolean.mjs",
"check:browser-occt": "node scripts/check-occt-browser-verification.mjs",
@@ -82,6 +83,10 @@
"test:freecad-cam-path-report": "node --test tests/freecadCamPathOracle.test.mjs",
"build:occt-history": "bash native/occt-history/build.sh",
"build:freecad-naming-worker": "FREECAD_WASM_NAMING_REQUIRED=1 bash native/occt-history/build.sh",
"build:qt6-wasm-core": "bash scripts/build-qt6-wasm-core.sh",
"build:freecad-naming-source-probe": "bash scripts/build-freecad-naming-source-probe.sh",
"test:freecad-naming-source-probe": "node native/freecad-naming-probe/smoke-test.mjs",
"test:freecad-private-naming-boundary": "node --test tests/freecadPrivateNamingBoundary.test.mjs",
"test:occt-history": "node native/occt-history/smoke-test.mjs",
"build:planegcs": "bash native/planegcs/build.sh",
"test:planegcs": "node native/planegcs/smoke-test.mjs",
@@ -269,7 +274,7 @@
"test:browser-matrix": "node scripts/run-browser-matrix.mjs",
"check:browser-matrix": "node scripts/check-browser-matrix.mjs",
"check:runtime": "node scripts/check-runtime.mjs",
"verify": "npm run check:runtime && npm run check:baseline && npm run check:bitbybit-history && npm run check:execution-plan && npm run check:freecad-sketcher-constraints && npm run check:freecad-inventory && npm run check:freecad-type-properties && npm run check:freecad-gui-commands && npm run check:freecad-entrypoints && npm run check:freecad-golden-fixtures && npm run check:freecad-semantic-comparator && npm run check:freecad-fcstd-roundtrip && npm run check:freecad-composite-history-elementmap && npm run check:freecad-exact-history-elementmap-gate && npm run check:freecad-native-naming-evidence && npm run check:fcstd-hardening && npm run check:freecad-naming-sdk && npm run check:occt-history-artifact && npm run check:planegcs-artifact && npm run check:browser-occt && npm run check:chrome-topology && npm run check:chrome-planegcs && npm run check:chrome-fault-injection && npm run check:chrome-opfs-migration && npm run check:chrome-persistence && npm run check:chrome-app-e2e && npm run check:chrome-partdesign-lifecycle && npm run check:pwa && npm run check:chrome-offline && npm run check:chrome-geometry-features && npm run check:chrome-native-history && npm run check:chrome-native-pad-history && npm run check:chrome-native-pocket-history && npm run check:chrome-native-loft-history && npm run check:chrome-native-pipe-history && npm run check:chrome-native-revolution-history && npm run check:chrome-native-groove-history && npm run check:chrome-native-fillet-history && npm run check:chrome-native-chamfer-history && npm run check:chrome-native-hole-history && npm run check:chrome-native-draft-history && npm run check:chrome-native-thickness-history && npm run check:chrome-native-linear-pattern-history && npm run check:chrome-native-polar-pattern-history && npm run check:chrome-native-mirrored-history && npm run check:chrome-native-multi-transform-history && npm run check:chrome-sketcher-diagnostics && npm run check:chrome-profile-validation && npm run check:chrome-sketcher-editor && npm run check:chrome-sketcher-bspline && npm run check:chrome-sketcher-stress && npm run check:chrome-part-primitives && npm run check:chrome-partdesign-transform && npm run check:chrome-partdesign-loft && npm run check:partdesign-closure && npm run check:chrome-fcstd-semantic && npm run check:chrome-fcstd-roundtrip && npm run check:fcstd-closure && npm run check:chrome-spreadsheet && npm run check:chrome-plot && npm run check:chrome-draft && npm run check:chrome-techdraw && npm run check:chrome-assembly && npm run check:chrome-mesh && npm run check:chrome-inspection && npm run check:chrome-bim && npm run check:chrome-cam && npm run check:cam-parity && npm run check:cam-pipeline && npm run check:opencamlib-wasm && npm run check:camotics-native && npm run check:camotics-gui-tpl && npm run check:camotics-wasm && npm run check:chrome-camotics-wasm && npm run check:chrome-cam-native-simulation && npm run check:chrome-cam-linuxcnc-machine && npm run check:chrome-fem && npm run check:chrome-robot && npm run check:chrome-data && npm run check:chrome-addon && npm run check:chrome-script && npm run check:chrome-surface && npm run check:chrome-qa08 && npm run check:chrome-secondary-formats && npm run check:chrome-performance && npm run check:chrome-production-document && npm run check:document-closure && npm run check:chrome-engineering && npm run check:chrome-security && npm run check:chrome-fcstd-golden && npm run check:sbom && npm run check:project-migration && npm run check:security-baseline && npm run check:dependency-audit && npm run check:freecad:threeway && npm run check:occt-upstream-drift && npm run check:facade-boundary && npm run test:golden && npm run test:spreadsheet && npm run test:plot && npm run test:draft && npm run test:techdraw && npm run test:assembly && npm run test:mesh && npm run test:inspection && npm run test:bim && npm run test:cam && npm run test:camotics-wasm && npm run test:fem && npm run test:robot && npm run test:data && npm run test:addon && npm run test:script && npm run test:surface && npm run test:locale && npm run test:secondary-formats && npm run test:performance && npm run test:production-document && npm run test:engineering && npm run test:security-preflight && npm run test:fcstd-roundtrip && npm run test:facade && npm run test:fcstd-fuzz && npm run test:geometry-input-fuzz && npm run test:sketch-solver-fuzz && npm run check:quality-closure && npm run test:planegcs && npm run test:project-migration && npm run test:sketcher-stress && npm run test:topology-replay && npm run build && npm run check:built-pwa && npm run generate:release-artifacts && npm run check:release-artifacts && npm run check:release-closure && npm run test:release-signature",
"verify": "npm run check:runtime && npm run check:baseline && npm run check:bitbybit-history && npm run check:execution-plan && npm run check:freecad-sketcher-constraints && npm run check:freecad-inventory && npm run check:freecad-type-properties && npm run check:freecad-gui-commands && npm run check:freecad-entrypoints && npm run check:freecad-golden-fixtures && npm run check:freecad-semantic-comparator && npm run check:freecad-fcstd-roundtrip && npm run check:freecad-composite-history-elementmap && npm run check:freecad-exact-history-elementmap-gate && npm run check:freecad-native-naming-evidence && npm run check:fcstd-hardening && npm run check:freecad-naming-sdk && npm run check:freecad-private-naming-boundary && npm run check:occt-history-artifact && npm run check:planegcs-artifact && npm run check:browser-occt && npm run check:chrome-topology && npm run check:chrome-planegcs && npm run check:chrome-fault-injection && npm run check:chrome-opfs-migration && npm run check:chrome-persistence && npm run check:chrome-app-e2e && npm run check:chrome-partdesign-lifecycle && npm run check:pwa && npm run check:chrome-offline && npm run check:chrome-geometry-features && npm run check:chrome-native-history && npm run check:chrome-native-pad-history && npm run check:chrome-native-pocket-history && npm run check:chrome-native-loft-history && npm run check:chrome-native-pipe-history && npm run check:chrome-native-revolution-history && npm run check:chrome-native-groove-history && npm run check:chrome-native-fillet-history && npm run check:chrome-native-chamfer-history && npm run check:chrome-native-hole-history && npm run check:chrome-native-draft-history && npm run check:chrome-native-thickness-history && npm run check:chrome-native-linear-pattern-history && npm run check:chrome-native-polar-pattern-history && npm run check:chrome-native-mirrored-history && npm run check:chrome-native-multi-transform-history && npm run check:chrome-sketcher-diagnostics && npm run check:chrome-profile-validation && npm run check:chrome-sketcher-editor && npm run check:chrome-sketcher-bspline && npm run check:chrome-sketcher-stress && npm run check:chrome-part-primitives && npm run check:chrome-partdesign-transform && npm run check:chrome-partdesign-loft && npm run check:partdesign-closure && npm run check:chrome-fcstd-semantic && npm run check:chrome-fcstd-roundtrip && npm run check:fcstd-closure && npm run check:chrome-spreadsheet && npm run check:chrome-plot && npm run check:chrome-draft && npm run check:chrome-techdraw && npm run check:chrome-assembly && npm run check:chrome-mesh && npm run check:chrome-inspection && npm run check:chrome-bim && npm run check:chrome-cam && npm run check:cam-parity && npm run check:cam-pipeline && npm run check:opencamlib-wasm && npm run check:camotics-native && npm run check:camotics-gui-tpl && npm run check:camotics-wasm && npm run check:chrome-camotics-wasm && npm run check:chrome-cam-native-simulation && npm run check:chrome-cam-linuxcnc-machine && npm run check:chrome-fem && npm run check:chrome-robot && npm run check:chrome-data && npm run check:chrome-addon && npm run check:chrome-script && npm run check:chrome-surface && npm run check:chrome-qa08 && npm run check:chrome-secondary-formats && npm run check:chrome-performance && npm run check:chrome-production-document && npm run check:document-closure && npm run check:chrome-engineering && npm run check:chrome-security && npm run check:chrome-fcstd-golden && npm run check:sbom && npm run check:project-migration && npm run check:security-baseline && npm run check:dependency-audit && npm run check:freecad:threeway && npm run check:occt-upstream-drift && npm run check:facade-boundary && npm run test:golden && npm run test:spreadsheet && npm run test:plot && npm run test:draft && npm run test:techdraw && npm run test:assembly && npm run test:mesh && npm run test:inspection && npm run test:bim && npm run test:cam && npm run test:camotics-wasm && npm run test:fem && npm run test:robot && npm run test:data && npm run test:addon && npm run test:script && npm run test:surface && npm run test:locale && npm run test:secondary-formats && npm run test:performance && npm run test:production-document && npm run test:engineering && npm run test:security-preflight && npm run test:fcstd-roundtrip && npm run test:facade && npm run test:fcstd-fuzz && npm run test:geometry-input-fuzz && npm run test:sketch-solver-fuzz && npm run check:quality-closure && npm run test:planegcs && npm run test:project-migration && npm run test:sketcher-stress && npm run test:topology-replay && npm run build && npm run check:built-pwa && npm run generate:release-artifacts && npm run check:release-artifacts && npm run check:release-closure && npm run test:release-signature",
"test:chrome-native-thickness-history": "node scripts/run-chrome-native-thickness-history.mjs",
"check:chrome-native-thickness-history": "node scripts/check-chrome-native-thickness-history.mjs",
"test:chrome-native-linear-pattern-history": "node scripts/run-chrome-native-linear-pattern-history.mjs",

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
FREECAD_SOURCE_DIR="${FREECAD_SOURCE_DIR:-${ROOT_DIR}/.cache/freecad/FreeCAD}"
QT6_WASM_DIR="${QT6_WASM_DIR:-${ROOT_DIR}/.cache/toolchains/qt6/install-wasm}"
OFFLINE_INCLUDE_DIR="${OFFLINE_INCLUDE_DIR:-${ROOT_DIR}/.cache/offline-sysroot/include}"
DIST_DIR="${ROOT_DIR}/native/freecad-naming-probe/dist"
SHIM_DIR="${ROOT_DIR}/native/freecad-naming-probe/shims"
FREECAD_COMMIT="0108fd4b4850cc46e625b60e53cea7a7bbe69f8d"
INDEXED_NAME_SHA256="73e0e60a9d6ee06851252e2071ebdd58698f8f99733903232529b3a194164435"
MAPPED_NAME_SHA256="90173aba5f331ac9453589833f7e5fc63c5c80a35f1600dbc71211606b1c9dbc"
if [[ ! -d "${FREECAD_SOURCE_DIR}/.git" ]] || [[ "$(git -C "${FREECAD_SOURCE_DIR}" rev-parse HEAD)" != "${FREECAD_COMMIT}" ]]; then
echo "FreeCAD private naming probe requires locked commit ${FREECAD_COMMIT}." >&2
exit 1
fi
printf '%s %s\n' \
"${INDEXED_NAME_SHA256}" "${FREECAD_SOURCE_DIR}/src/App/IndexedName.cpp" \
"${MAPPED_NAME_SHA256}" "${FREECAD_SOURCE_DIR}/src/App/MappedName.cpp" | sha256sum -c -
if [[ "$(emcc --version | sed -n '1s/.* \([0-9][0-9.]*\) .*/\1/p')" != "3.1.69" ]]; then
echo "FreeCAD private naming probe requires Emscripten 3.1.69." >&2
exit 1
fi
for path in \
"${QT6_WASM_DIR}/include/QtCore/QByteArray" \
"${QT6_WASM_DIR}/lib/libQt6Core.a" \
"${QT6_WASM_DIR}/lib/libQt6BundledPcre2.a" \
"${QT6_WASM_DIR}/lib/libQt6BundledZLIB.a"; do
if [[ ! -s "${path}" ]]; then
echo "Missing Qt6 wasm Core prerequisite: ${path}" >&2
exit 1
fi
done
if [[ ! -s "${OFFLINE_INCLUDE_DIR}/boost/signals2/signal.hpp" ]]; then
echo "Missing offline Boost headers: ${OFFLINE_INCLUDE_DIR}" >&2
exit 1
fi
mkdir -p "${DIST_DIR}"
em++ \
"${ROOT_DIR}/native/freecad-naming-probe/probe.cpp" \
"${FREECAD_SOURCE_DIR}/src/App/IndexedName.cpp" \
"${FREECAD_SOURCE_DIR}/src/App/MappedName.cpp" \
-I"${SHIM_DIR}" \
-include "${SHIM_DIR}/App/StringHasher.h" \
-I"${FREECAD_SOURCE_DIR}/src" \
-I"${QT6_WASM_DIR}/include" \
-I"${QT6_WASM_DIR}/include/QtCore" \
-I"${OFFLINE_INCLUDE_DIR}" \
-std=c++17 -Oz -fexceptions --bind \
-Wl,--start-group \
"${QT6_WASM_DIR}/lib/libQt6Core.a" \
"${QT6_WASM_DIR}/lib/libQt6BundledPcre2.a" \
"${QT6_WASM_DIR}/lib/libQt6BundledZLIB.a" \
-Wl,--end-group \
-sMODULARIZE=1 -sEXPORT_ES6=1 -sENVIRONMENT=web,worker,node \
-sALLOW_MEMORY_GROWTH=1 -sNO_EXIT_RUNTIME=1 \
-o "${DIST_DIR}/freecad-private-naming-source-probe.js"
sha256sum "${DIST_DIR}/freecad-private-naming-source-probe.js" "${DIST_DIR}/freecad-private-naming-source-probe.wasm"

96
scripts/build-qt6-wasm-core.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
QT_VERSION="6.8.2"
QT_ARCHIVE="qtbase-everywhere-src-${QT_VERSION}.tar.xz"
QT_ARCHIVE_SHA256="012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05"
QT_CACHE_DIR="${QT6_WASM_CACHE_DIR:-${ROOT_DIR}/.cache/toolchains/qt6}"
QT_DOWNLOAD_DIR="${QT_CACHE_DIR}/downloads"
QT_SOURCE_DIR="${QT_CACHE_DIR}/src"
QT_BUILD_DIR="${QT_CACHE_DIR}/build-wasm"
QT_INSTALL_DIR="${QT_CACHE_DIR}/install-wasm"
EMSDK_SHIM_DIR="${QT_CACHE_DIR}/emsdk-shim"
JOBS="${JOBS:-$(nproc)}"
if ! command -v emcc >/dev/null || ! command -v em++ >/dev/null; then
echo "Emscripten emcc/em++ are required." >&2
exit 1
fi
if [[ "$(emcc --version | sed -n '1s/.* \([0-9][0-9.]*\) .*/\1/p')" != "3.1.69" ]]; then
echo "Qt wasm Core must use the project-locked Emscripten 3.1.69 toolchain." >&2
exit 1
fi
mkdir -p "${QT_DOWNLOAD_DIR}" "${QT_CACHE_DIR}" "${EMSDK_SHIM_DIR}/upstream"
if [[ ! -f "${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}" ]]; then
if [[ "${WEB_FREECAD_OFFLINE:-0}" == "1" ]]; then
echo "Missing offline Qt source archive: ${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}" >&2
exit 1
fi
QT_ARCHIVE_PART="${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}.part"
curl -fL --retry 3 --retry-delay 2 \
"https://mirrors.ustc.edu.cn/qtproject/archive/qt/6.8/${QT_VERSION}/submodules/${QT_ARCHIVE}" \
-o "${QT_ARCHIVE_PART}"
printf '%s %s\n' "${QT_ARCHIVE_SHA256}" "${QT_ARCHIVE_PART}" | sha256sum -c -
mv "${QT_ARCHIVE_PART}" "${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}"
fi
printf '%s %s\n' "${QT_ARCHIVE_SHA256}" "${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}" | sha256sum -c -
if [[ ! -x "${QT_SOURCE_DIR}/configure" ]]; then
mkdir -p "${QT_SOURCE_DIR}"
tar -xJf "${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}" -C "${QT_SOURCE_DIR}" --strip-components=1
fi
printf '%s\n' "EMSCRIPTEN_ROOT = emsdk_path + '/upstream/emscripten'" > "${EMSDK_SHIM_DIR}/.emscripten"
ln -sfn /usr/share/emscripten "${EMSDK_SHIM_DIR}/upstream/emscripten"
ln -sfn "$(command -v emcc)" "${EMSDK_SHIM_DIR}/emcc"
ln -sfn "$(command -v em++)" "${EMSDK_SHIM_DIR}/em++"
mkdir -p "${QT_BUILD_DIR}" "${QT_INSTALL_DIR}"
if [[ ! -f "${QT_BUILD_DIR}/build.ninja" ]]; then
(
cd "${QT_BUILD_DIR}"
EMSDK="${EMSDK_SHIM_DIR}" "${QT_SOURCE_DIR}/configure" \
-platform wasm-emscripten \
-qt-host-path /usr \
-prefix /qt \
-extprefix "${QT_INSTALL_DIR}" \
-static -release -optimize-size \
-no-gui -no-widgets -no-dbus -no-feature-network -no-feature-thread \
-nomake examples -nomake tests -nomake benchmarks -nomake manual-tests \
-no-pch -no-sbom \
-- -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=/usr/share/emscripten/cmake/Modules/Platform/Emscripten.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DQT_BUILD_TOOLS_WHEN_CROSSCOMPILING=OFF \
-DQT_FEATURE_wasm_simd128=OFF \
-DQT_FEATURE_wasm_exceptions=OFF \
-DQt6HostInfo_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt6HostInfo
)
fi
cmake --build "${QT_BUILD_DIR}" --target Core --parallel "${JOBS}"
cmake --install "${QT_BUILD_DIR}" --component Devel
cmake --install "${QT_BUILD_DIR}/src/corelib"
for path in \
"${QT_BUILD_DIR}/lib/libQt6Core.a" \
"${QT_BUILD_DIR}/lib/libQt6BundledPcre2.a" \
"${QT_BUILD_DIR}/lib/libQt6BundledZLIB.a"; do
if [[ ! -s "${path}" ]]; then
echo "Qt wasm Core output is missing: ${path}" >&2
exit 1
fi
cp -f "${path}" "${QT_INSTALL_DIR}/lib/$(basename "${path}")"
done
if [[ ! -s "${QT_INSTALL_DIR}/include/QtCore/QByteArray" ]]; then
echo "Qt wasm Core headers were not installed into ${QT_INSTALL_DIR}." >&2
exit 1
fi
sha256sum \
"${QT_DOWNLOAD_DIR}/${QT_ARCHIVE}" \
"${QT_INSTALL_DIR}/lib/libQt6Core.a" \
"${QT_INSTALL_DIR}/lib/libQt6BundledPcre2.a" \
"${QT_INSTALL_DIR}/lib/libQt6BundledZLIB.a"

View File

@@ -0,0 +1,31 @@
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
const root = resolve(new URL('..', import.meta.url).pathname)
const load = async (path) => JSON.parse(await readFile(resolve(root, path), 'utf8'))
const [abi, matrix, plan] = await Promise.all([
load('config/freecad-sketcher-partdesign-abi-contract.json'),
load('config/compatibility-matrix.json'),
load('config/freecad-web-exact-parity-plan.json'),
])
const fail = (message) => { throw new Error(`FreeCAD private naming boundary: ${message}`) }
const tasks = plan.programs.flatMap((program) => program.tasks)
const task = tasks.find((entry) => entry.id === 'EX-TSN-02')
if (!task) fail('EX-TSN-02 is missing from the exact parity plan.')
if (abi.privateNamingAbi?.shippedWorkerImplementation !== 'not-linked') fail('the shipped ABI contract must remain not-linked until the production artifact exports verified callbacks.')
if (abi.claim?.exactFreeCadParity !== false) fail('the supported facade contract cannot claim exact FreeCAD parity.')
if (matrix.nativeOcctHistory?.freecadNamingBuild?.status !== 'contract-only') fail('the FreeCAD naming build must remain contract-only before a locked SDK and callback probe exist.')
if (task.status !== 'in_progress') fail(`EX-TSN-02 must remain in_progress, received ${String(task.status)}.`)
if (matrix.systemExactEvaluation?.exact !== false) fail('systemExact must remain false.')
const blockers = matrix.systemExactEvaluation?.blockers ?? []
if (!blockers.includes('shipped Worker lacks the FreeCAD-linked private naming ABI implementation')) fail('systemExact blockers must retain the missing FreeCAD-linked Worker implementation.')
if (!task.exactBlockedBy?.includes('The shipped Worker does not link the FreeCAD private naming implementation for every builder')) fail('EX-TSN-02 must retain its production Worker linkage blocker.')
console.log(JSON.stringify({
status: 'boundary-pass',
shippedWorkerImplementation: 'not-linked',
task: { id: task.id, status: task.status },
systemExact: matrix.systemExactEvaluation.exact,
sdkStatus: matrix.nativeOcctHistory.freecadNamingBuild.status,
}, null, 2))

View File

@@ -607,7 +607,7 @@ async function smoke() {
FREECAD_SOURCE_OFFLINE: '1',
OCCT_SOURCE_DIR: resolve(root, '.cache/occt/occt'),
}
for (const script of ['check:runtime', 'check:freecad-source', 'check:occt-history-artifact', 'test:occt-history', 'test:planegcs', 'build']) {
for (const script of ['check:runtime', 'check:freecad-source', 'check:freecad-private-naming-boundary', 'check:occt-history-artifact', 'test:occt-history', 'test:planegcs', 'build']) {
print(`[offline:smoke] npm run ${script}`)
await run(resolve(root, 'npmw'), ['run', script], { env: environment })
}

View File

@@ -81,6 +81,7 @@ const lanes = {
wasm: [
...wasmBuilds,
'check:occt-history-artifact',
'check:freecad-private-naming-boundary',
'test:browser-occt',
'check:browser-occt',
'test:planegcs',

View File

@@ -0,0 +1,42 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
const root = resolve(new URL('..', import.meta.url).pathname)
test('Qt wasm Core build pins the released QtBase source and project Emscripten baseline', async () => {
const source = await readFile(resolve(root, 'scripts/build-qt6-wasm-core.sh'), 'utf8')
assert.match(source, /QT_VERSION="6\.8\.2"/)
assert.match(source, /012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05/)
assert.match(source, /Emscripten 3\.1\.69/)
assert.match(source, /mirrors\.ustc\.edu\.cn/)
assert.match(source, /WEB_FREECAD_OFFLINE/)
assert.match(source, /cmake --install "\$\{QT_BUILD_DIR\}\/src\/corelib"/)
assert.doesNotMatch(source, /cmake --install[^\n]+\|\| true/)
})
test('FreeCAD source probe pins the exact private source inputs and does not export the production ABI', async () => {
const build = await readFile(resolve(root, 'scripts/build-freecad-naming-source-probe.sh'), 'utf8')
const smoke = await readFile(resolve(root, 'native/freecad-naming-probe/smoke-test.mjs'), 'utf8')
assert.match(build, /0108fd4b4850cc46e625b60e53cea7a7bbe69f8d/)
assert.match(build, /73e0e60a9d6ee06851252e2071ebdd58698f8f99733903232529b3a194164435/)
assert.match(build, /90173aba5f331ac9453589833f7e5fc63c5c80a35f1600dbc71211606b1c9dbc/)
assert.doesNotMatch(build, /public\/native\/freecad-naming-probe/)
for (const callback of ['freecadNamingAbiVersion', 'freecadNamingCapabilitiesJson', 'freecadNamingEvidenceJson']) {
assert.match(smoke, new RegExp(callback))
}
assert.match(smoke, /productionWorkerLinked: false/)
})
test('private naming boundary checker cross-validates all authoritative status files', async () => {
const source = await readFile(resolve(root, 'scripts/check-freecad-private-naming-boundary.mjs'), 'utf8')
for (const path of [
'config/freecad-sketcher-partdesign-abi-contract.json',
'config/compatibility-matrix.json',
'config/freecad-web-exact-parity-plan.json',
]) assert.match(source, new RegExp(path.replaceAll('.', '\\.')))
assert.match(source, /shippedWorkerImplementation !== 'not-linked'/)
assert.match(source, /task\.status !== 'in_progress'/)
assert.match(source, /systemExactEvaluation\?\.exact !== false/)
})

View File

@@ -39,6 +39,9 @@ test('offline profile covers runtime, native sources, browsers and host recovery
'linuxcnc-worktree',
'occt-history-dist',
'planegcs-dist',
'qt6-wasm-core-downloads',
'qt6-wasm-core-source',
'qt6-wasm-core-sdk',
'playwright-browsers',
'debian-package-cache',
]) assert.ok(ids.has(id), id)