83 lines
8.7 KiB
Markdown
83 lines
8.7 KiB
Markdown
# FreeCAD Web 实现优先移植策略
|
||
|
||
2026-09-08 当前调度与上下文规则以 `WEB_DELIVERY_CONTEXT_PLAN.md` 为准:优先复用已有成果交付工作区、文档、建模和文件闭环;当前业务结果确认是必须步骤,不受下方历史“验证后置”条款禁止。完整 API/Full Parity/浏览器矩阵仍不在每个小批次重复执行,全部业务范围保留。
|
||
|
||
## 决策
|
||
|
||
当前执行目标从“逐条 API 先取得 evidence 再推进”切换为“先完成用户可操作的 Web 功能链,使用过程中发现问题再定点修复”。
|
||
|
||
这不是删除 FreeCAD 源程序,也不是允许静态结果或假实现。所有实际计算、Document、对象、格式、Python 和持久化行为仍必须来自 `freecad-source` 构建出的 WASM/native dispatcher;变化的是调度顺序和完成判据:
|
||
|
||
- 不再以 `apiExposed` 作为实现阶段的主进度;
|
||
- 不在每个小批次之后运行 focused gate、完整 API gate、Full Parity gate 或 Chrome 矩阵;
|
||
- 只在需要启动/链接目标时做最小的构建、类型、资源和入口检查;
|
||
- 浏览器使用中出现真实问题时,生成一个最小复现和修复记录,再对受影响功能链定点处理;
|
||
- 完整验证保留为后置工作,不得把未验证内容写成 `pass`。
|
||
|
||
## `13,386` 的审计结论
|
||
|
||
`13,386` 不是“FreeCAD 全部用户功能”的数量,也不是 Web 必须创建的 13,386 个公开函数。
|
||
|
||
1. 扫描器解析了 1,546 个 `.py/.pyi` 文件,跳过 233 个 test-like 文件和 4 个语法无法解析的文件。去重前命中 **14,709** 个节点(class 2,201、function 3,047、method 9,461)。
|
||
2. `docs/format-api-inventory.json` 的成品清单是 **13,385** 条:class 2,053、function 2,380、method 8,952,覆盖 29 个模块。生成器用 `(module, kind, name)` 做 `setdefault`,实际折叠了 1,324 个源码节点、涉及 362 个冲突 key;所以成品“无重复”是去重算法的结果,不表示源码没有同名定义。
|
||
3. `docs/p6/python-api-manifest.json` 目前是 **13,386** 条,多出的 1 条是 `py:Part:function:makeBox`。它来自 C++ Python binding `AppPartPy.cpp` 的专门 gate,不在当前只扫描 `.py/.pyi` 的 AST inventory 中。因此这是“源码 Python inventory + 手工补入的 C++ binding”,不是同一口径的全量数字。
|
||
4. inventory 不覆盖完整 C++ Python 注册、导入/别名、继承所得 API、动态命令或嵌套定义;同时把所有不以下划线开头的实现函数都视为 public,可能把内部 helper 算成 API。因此它既会漏计,也会过计。
|
||
5. `Import/App/SCL_output/config_control_design.py` 单文件约 1,007 条记录,是 fedex 生成的 STEP/EXPRESS schema 类和规则,不等于 1,007 个用户界面功能。
|
||
6. 按路径/名称做保守的 GUI 线索统计约 3,647 条(27.2%),其中 TaskPanel、ViewProvider、Command、Gui 路径高度重叠;这些能力在无头 WASM 中需要 React 交互等价物,不应直接当作可暴露 Python 函数。
|
||
7. 目前 `restricted` 和 `not_implemented` 主要表示运行时边界或尚未建立 typed fixture,不表示对应的 Web 用户功能永远不存在。
|
||
|
||
因此,13,386 应保留为“可追溯源符号索引”,不能继续作为移植队列长度、页面数量或功能完成率分母。实现阶段必须另建 capability 口径。
|
||
|
||
## 四层状态模型
|
||
|
||
| 层 | 文件/来源 | 作用 | 是否阻断实现 |
|
||
|---|---|---|---|
|
||
| 源符号索引 | `docs/format-api-inventory.json`、`docs/p6/python-api-manifest.json` | 保留源码身份、模块、family、tier 和证据路径 | 否 |
|
||
| 功能能力注册 | `docs/current/feature-capability-registry.json` | 记录一个用户功能链对应的 command、Worker、WASM 模块和涉及 API | 否 |
|
||
| 实现回执 | `docs/current/implementation-first-registry.json` | 记录已完成接线/构建的批次,防止同一批重复领取 | 否 |
|
||
| 使用问题 | `docs/current/runtime-issue-ledger.json` | 用户或运行时发现问题的最小复现、首错、修复和重新部署范围 | 仅阻断受影响功能 |
|
||
|
||
API manifest 的 `disposition` 只有在明确的后置验证阶段才更新。实现回执不能把 `planned` 伪装成 `exposed`,也不能因为一个功能链已可用就关闭所有相关 API 记录。
|
||
|
||
## 新的实现顺序
|
||
|
||
按用户可观察工作流推进,每个工作流内部仍批量复用一个 `fc_web_dispatch_json({cmd,args})`、一个 Facade/Worker 和一个独立 WASM 模块:
|
||
|
||
1. 核心工作区:创建/打开/保存 Document、对象树、属性编辑、选择、重算、Undo/Redo、恢复。
|
||
2. 建模主链:Part 基本体、布尔/变换、PartDesign 特征、Sketcher 几何和约束。
|
||
3. 视图交互:Three.js 场景、选择高亮、相机、显示模式、属性面板和导航。
|
||
4. 文件链:FCStd、STEP/IGES/BREP/STL/OBJ/SVG/DXF/IFC 等实际可用的 import/export 路由。
|
||
5. 工程工作台:TechDraw、Mesh、Fem、BIM/IFC、Assembly、CAM、Measure。
|
||
6. 扩展和长尾:Python family、插件、模板、辅助工作台和可明确映射的 GUI 命令。
|
||
|
||
每条工作流先完成“入口 → native handler → Worker → React 页面 → 错误恢复”的连续路径,再扩展同一路径的 API 别名。禁止为每个符号单独创建 WASM export、Worker 或页面。
|
||
|
||
Desktop command 使用生成式通道:`workbench-command-matrix.json` 提供命令身份和源码位置,生成器从 native `FC_WEB_DESKTOP_COMMAND(...)` 或 `QStringList` 注册中确定实现所有者,并产出 `desktop-command-routes.json`。React `DesktopCommandDispatcher` 依据该索引选择 `family-batch` 或 `direct-command` transport,模块 Worker 按需加载对应独立 WASM。结果必须从请求参数和真实 BREP/mesh/Document 数据计算,不能在 React/Facade 维护逐命令固定参数、fixture 或结果;跨工作台出现的同名命令复用 canonical 实现。
|
||
|
||
`Workbench.cpp` 中带子项的 `MenuItem/ToolBarItem.setCommand()` 是导航容器,不是可执行命令。生成器通过后续 `*item << ...` 或 `add...(*item)` 关系自动识别,并生成 `ui-container` route,由 React 呈现菜单/工具栏分组;只有叶子命令进入 WASM 实现队列。这样不会为了 `Constraints`、`Dimensions`、`Boolean` 等分组标题制造假的 native handler。
|
||
|
||
为了避免 Emscripten 无增量最终链接带来的重复成本,外层 pipeline 在构建前刷新 capability registry。只要当前批次还有一个 selected ID 缺少 native registration、family Facade/Worker 或 React 通用入口,就以 `implementation_incomplete` 返回且不构建。静态接线全部完成后只构建一次。构建缓存从 `build.ninja` 解析当前 target 的 object→source 映射,不因同模块其它 probe 改动失效。
|
||
|
||
## 回合规则
|
||
|
||
- 外层 planner 可以继续使用 API manifest 选择源码输入,但实现回执负责去重;已经有回执的记录不再次领取,除非 runtime issue 明确重新打开。
|
||
- Codex 回合只做源码判断、接线、依赖补充、WASM 构建和资源同步;不要主动运行 focused gate 或完整验证。
|
||
- 若源码没有可用 native handler,只登记 `native_source_required`/`blocked_native_dependency`,继续领取其它功能链;不生成假的 JS 结果。
|
||
- 构建只针对变更目标使用 `-j8`(或 `FREECAD_BUILD_JOBS`),并保留独立模块 artifact 和动态加载 manifest;不合并 WASM。
|
||
- 构建失败只修复首错一次;无法从本地源码解决时记录 issue,立即转到下一个不受影响的功能链。
|
||
- 使用阶段的错误处理流程是:记录 request/args/source revision/artifact hash → 定点复现 → 最小修复 → 重新构建受影响模块 → 更新 issue 状态。不要触发全量验证。
|
||
|
||
观察到问题时使用以下入口写入定点队列;scheduler 会因 ledger 指纹变化自动领取对应 capability:
|
||
|
||
```sh
|
||
python3 tools/record_runtime_issue.py 'Part:part.createRecompute' \
|
||
--args-json '{"schema":"...","module":"Part"}' \
|
||
--error '实际观察到的首错或错误行为'
|
||
```
|
||
|
||
## 新的进度口径
|
||
|
||
状态页必须同时显示 `featureCapabilities`、`implementationReceipts`、`apiExposed`、`apiClassified`、`runtimeIssues` 和 `fullParity`。capability 总量由动态发现的 Web command 与源码盘点的桌面 Qt/Gui command 合并生成;后者只有得到 Web route、Worker、React 入口和参数化 native registration 后才能写实现回执。具体数量始终读取 registry,不在执行规则中固化。`apiExposed` 仅表示已有运行时 evidence 的源符号,不能代表 Web 功能完成率。
|
||
|
||
最终 Full Parity 仍需要用户明确触发的集中验证;实现优先阶段不得用“暂不验证”宣布项目完成,也不得因验证缺失阻断继续实现。
|