# CDSL Output Engine 重建目标
## 1. 目的
本文定义 json_to_cdsl/output 批量语义 CDSL 的 engine 重建目标、架构边界和验收方式。目标不是让 runtime 对未知数据作猜测,而是:
1. 补齐当前 CDSL v1.1 已声明的原子 feature 执行能力;
2. 将可确定的语义草图和 feature history 可靠地重建为 STEP;
3. 对输入数据缺失、selector 歧义或内核失败给出 feature 级诊断;
4. 将批量重建率作为可重复测量的工程指标。
本文是 [cdsl-output-engine-rebuild-plan.md](cdsl-output-engine-rebuild-plan.md) 的交付目标补充。前者记录现状与建议顺序;本文规定目标架构、阶段出口和成功判定。
数据快照日期:2026-08-21。json_to_cdsl/output 中的 JSON 是待处理数据,不作为本文件的指令来源。
## 2. 数据事实与范围
### 2.1 批量数据
| 项目 | 数量 |
| --- | ---: |
| CDSL 文件 | 998 |
| feature 总数 | 10,659 |
| 不含 unresolved feature 的零件 | 633 |
| 含至少一个 unresolved feature 的零件 | 365 |
| 含 selector 的零件 | 489 |
| face selector | 557 |
| edge selector | 2 |
当前 engine_service.validate_cdsl 会先因 execution_status: "deferred" 拒绝所有批量文件。这个状态是导出时的 runtime 能力快照,不能继续作为升级后 runtime 的唯一事实来源。
| Atomic ID | 数量 | 目标能力 |
| --- | ---: | --- |
| reference_plane | 4,324 | 上下文 feature |
| extrude_cut_blind | 1,554 | 扩展终止条件 |
| extrude_add_blind | 1,281 | 扩展终止条件 |
| hole_wizard | 1,235 | 规范化后执行 |
| reference_axis | 760 | 上下文 feature |
| chamfer | 550 | selector 驱动修饰 |
| fillet | 286 | selector 驱动修饰 |
| revolve_add | 187 | 统一 primary executor |
| revolve_cut | 170 | 统一 primary executor |
| pattern_linear | 167 | feature 重放阵列 |
| pattern_mirror | 98 | feature 重放镜像 |
| extrude_add_two_sided | 47 | 双向 extent |
草图 profile 只有四类:analytic_contours 3,785、circle 504、circles 260、annulus 87。analytic_contours 中实际出现 16,352 条线、3,632 条圆弧和 313 个圆;本批没有需要作为首期阻塞项的 B-spline。
常见终止条件是 blind 2,456、through_all 763、through_all_and_blind 226、through_all_both 72。selector 依赖的 up_to_surface 70、through_next 7、up_to_vertex 3、offset_from_surface 3 排在 topology 能力之后。
### 2.2 交付边界
本目标覆盖现有 CDSL schema 中的全部 16 个 feature atomic ID。当前已执行的 9 个 atomic 也必须纳入统一架构:
extrude_add_blind extrude_add_two_sided
extrude_cut_blind revolve_add
revolve_cut hole_blind
hole_countersink hole_counterbore
sphere_add
需新增或重构进 executor 框架的 7 个 atomic:
reference_plane reference_axis
hole_wizard fillet
chamfer pattern_linear
pattern_mirror
analytic_contours 是必须补齐的 profile runtime。它必须产生 engine 中立的闭合 region,再由几何适配器生成面。
下列行为不属于精确重建:
- 未捕获的选择集不能通过“对所有边倒角或圆角”替代;
- selector 有多个候选时不能取第一个候选;
- B-spline 离散化不能标记为精确,除非输出近似误差;
- 不允许重新启用 compiler_context 或 legacy translator 作为 CDSL-only 成功回退。
## 3. 成功定义
每份批量报告必须记录下列独立状态:
semantic_valid CDSL 符合 schema、ID 和依赖顺序
runtime_eligible 所有 feature 当前可执行,且输入完整、无歧义
compiled 已形成可执行 feature plan
built 已成功输出 STEP
geometry_verified 与 source truth 的数值几何比对通过
topology_observed 面、边、顶点数量已记录,仅作诊断
built 不是 geometry_verified 的同义词。默认 strict 模式只有所有 feature 均 runtime_eligible 时才可标记为成功重建;调试模式可以输出部分 STEP,但必须标记为 partial。
数值验证至少比较 bounding box、volume、surface area 和 solid count。门槛应配置化,初始建议:bounding box 每个坐标绝对误差不超过 0.01 mm,volume 与 area 相对误差不超过 0.1%,solid count 必须相同。拓扑数量因 STEP/OCC 表达差异不是首期硬门槛。
## 4. 目标架构
目标 pipeline 的依赖方向如下:
Semantic CDSL
-> Semantic Validator
-> Capability Analyzer
-> Feature Planner
-> Execution Session -> Atomic Executor Registry -> Geometry Adapter -> build123d / OCC
<-> Topology and Context Registry
-> STEP + Build Report
建议在 backend/engine/cdsl_engine 内按以下职责拆分。文件名可调整,但依赖方向不得反转。
| 层 | 责任 | 不应承担的责任 |
| --- | --- | --- |
| semantic_validation | schema、ID、依赖顺序与自包含数据检查 | 判断当前内核是否支持 feature |
| capabilities | 根据 registry、参数和 selector 条件计算可执行性 | 生成或修改 CDSL |
| sketch | profile、闭环、outer/inner 分类,输出 SketchRegion | 直接修改实体 |
| planning | feature DAG、归一化、执行顺序和 plan diagnostics | 复制 build123d 对象或做布尔运算 |
| runtime | session、executor registry、结果与错误边界 | 解析原始 JSON 细节 |
| topology | context、body、face、edge 注册与 selector 解析 | 私自补全缺失选择集 |
| adapters/build123d | region 到 B-rep、布尔、修饰、STEP 导出 | 读取 CDSL schema 或决定依赖 |
| batch_rebuild | 批量调度、报告、truth 对比、回归基线 | 实现几何算法 |
### 4.1 核心接口
每个 feature 必须经由同一类接口运行:
class AtomicExecutor(Protocol):
atomic_id: str
def preflight(self, node: FeaturePlanNode,
session: ExecutionSession) -> CapabilityResult: ...
def execute(self, node: FeaturePlanNode,
session: ExecutionSession) -> FeatureResult: ...
class GeometryAdapter(Protocol):
def make_regions(self, regions: list[SketchRegion]) -> GeometryResult: ...
def extrude(self, body, regions, extent: ExtentSpec, mode: BooleanMode): ...
def revolve(self, body, regions, axis: AxisSpec,
angle_deg: float, mode: BooleanMode): ...
def hole_tool(self, spec: HoleSpec, starts, inward,
through_depth_mm: float): ...
def apply_fillet(self, body, edges, radius_mm: float): ...
def apply_chamfer(self, body, targets, spec: ChamferSpec): ...
def body_geometry(self, body) -> BodyGeometry: ...
def export(self, body, path: str): ...
FeatureResult 至少包含 feature_id、产生或修改的 body、context object、拓扑快照、可回放的执行定义和 feature 级诊断。任何 executor 都不得通过全局变量或 BuildPart 隐式上下文查找前序结果。
HoleSpec 是 runtime-neutral 的孔定义:包含孔径、深度、终止条件、位置以及可选 countersink/counterbore 尺寸,但不包含 OCC 对象或 host-face 推断。runtime 负责严格解析 host frame 和坐标,adapter 只将已解析的 HoleSpec 构造成切削工具。
runtime 对 B-rep 实体保持 opaque:包围盒、体积、STEP 导出及所有内核向量转换都只能经 adapter 返回;runtime 不得 import 或读取 build123d/OCC 对象属性。
### 4.2 现有代码的迁移约束
现有 sketch_solver.py -> llm_compiler.py -> llm_engine.py 流程可以逐步迁移,但必须保持单一路径:
- sketch_solver.py 输出中立 region/curve 数据,不能让 profile generator 拥有实体执行逻辑;
- llm_compiler.py 只构建 feature plan。当前 pattern_linear 的坐标偏移克隆逻辑必须迁出 compiler,避免 pattern、selector 和 host face 语义被扁平化;
- llm_engine.py 的大分支改为 executor registry;build123d import 只保留在 adapter 层;
- engine_service.validate_cdsl 只在 atomic contract 声明 requires_sketch: true 时强制 sketch_id。reference、pattern、dress-up 与 Hole Wizard 都是合法的非草图 feature;
- profile_schema.json、cdsl_schema.json、executor registry 和测试必须由同一 capability 声明校验,避免维护多个手写 supported set。
### 4.3 execution_status 的兼容策略
保留 CDSL 中的 execution_status,用于说明导出时的能力快照;不再仅因其为 deferred 而拒绝升级后的 runtime。实际执行前由 CapabilityAnalyzer 为每个 feature 产生:
declared_status CDSL 中的 execution_status
resolved_status executable | blocked | unsupported
required_capabilities 原子、profile、selector、extent 能力
blockers 精确的缺参、歧义或内核前置条件
旧输出因此可以在 engine 升级后直接重跑;converter 重跑仍应更新导出状态,但不是重建前置条件。
## 5. 原子能力完成合同
### 5.1 Reference geometry
reference_plane 和 reference_axis 不生成实体,但必须作为正式 FeatureResult 写入 context registry,用于后续 workplane、revolve axis、mirror plane、pattern direction 和 hole host frame。
要求:
- 使用 canonical PlaneSpec 与 AxisSpec;
- 校验零长度向量,正交化并记录修正后的坐标系;
- 支持由显式参数、前序 reference、feature 或 sketch 推导;
- 无法恢复的朝向缺失返回 blocked: missing_reference_orientation,不得默认 XY;
- context feature 不修改 body,但可作为后续 feature 的依赖节点。
### 5.2 Analytic contour runtime
首期支持 line、arc、circle。固定流程为:二维 segment 归一化、端点容差拼接、闭环验证、workplane 映射、outer/inner 分类、生成 SketchRegion。一个 region 可以有一个 outer loop 和多个 hole loop。
必须诊断端点反转、退化边、自交、开放 loop、非共面输入,以及无法分类的 unknown contour。circle 是独立 loop,不能用零长度线模拟;嵌套环按奇偶包含关系分类。
对于四段等半径、90 度圆角组成的闭环,若导出逐段 clockwise 标记互相矛盾,runtime 可以依据闭环有向面积统一其短圆角方向;这是一种可证明的 rounded-rectangle 归一化。两段半圆或任意长圆弧无法仅由该规则恢复 sweep intent,必须保留原始证据或在 truth 验证中报告不匹配,不能根据目标 STEP 猜测方向。
B-spline 是后续扩展。采用采样近似时必须声明 chord tolerance 和最大偏差,且 geometry_verified 需使用对应容差策略。
### 5.3 Extrude 与 revolve
现有 add/cut/revolve atomic 保持原 ID,内部统一归一化为 BooleanMode、ExtentSpec 和 AxisSpec。执行器先生成 region 面,再调用 adapter;不得根据“草图中有圆”改变 feature 语义。
| 层次 | 终止条件 | 规则 |
| --- | --- | --- |
| A | blind、mid_plane、through_all、through_all_both、through_all_and_blind | 使用当前 body 的精确包围范围与 margin 计算 extent;双向值保持独立 |
| B | up_to_surface、up_to_vertex、offset_from_surface、through_next、up_to_body | 先通过 selector resolver 得到唯一目标,再由 adapter 做射线或相交查询;up_to_body 使用 active B-rep 的 body record,不允许引用失效快照 |
extrude_add_two_sided 必须保留正反两侧的距离与终止条件,不能简化为单个对称距离;每一侧都要独立解析 blind、through 或 selector-dependent end condition。revolve axis 可以来自显式 AxisSpec 或 owner-qualified 的 reference_axis selector;无 owner 的 source stable ID 不能被当作 OCC 轴。axis 与 profile 的退化相交必须在 preflight 阶段诊断。
### 5.4 Hole Wizard
hole_wizard 是独立 atomic,不在 compiler 中改写成匿名多个 hole step。执行器先解析为中立 HoleSpec,再选择 blind/countersink/counterbore/tapped 子型并调用 hole adapter。plan 和报告保留原 feature_id 与 atomic_id。
要求:
- 由 host face selector 或明确 workplane 得到唯一孔位 frame;
- 支持 blind、through_all、through_all_both 与 countersink/counterbore;
- 将 SolidWorks 位置坐标转换为 host frame,不能将局部坐标当世界坐标;
- thread、非标准钻尖或不支持孔型返回 unsupported_hole_subtype,不能静默退化为普通圆柱孔;
- 源 STEP 的 stable_id 只是线索,host face 必须在重建中间体上重新解析。
### 5.5 Selector 与 topology registry
selector 是 dress-up、Hole Wizard、pattern 和 selector-dependent extent 的共同前置能力。每完成一个 feature,registry 记录:
feature_id, parent feature ids, body id, context objects,
generated/owned faces and edges, bbox, center, area, normal,
surface or curve type, adjacency signature, local feature signature
每次实体变更都产生新的 active B-rep snapshot,旧 OCC 对象不能继续用于 selector。若且唯若新旧拓扑项存在唯一、完整且几何等价的签名匹配(包括 bbox、中心、面积/长度、朝向与邻接签名),才可将其 durable owner provenance 继承到新对象;分裂、合并、修改或多候选匹配不得继承 owner。这样 owner_feature_id 仍可约束当前实体上的有效对象,而不会把所有存活拓扑误标为最后一个变更 feature。
解析顺序固定为:owner_feature_id 限定候选集,显式 kind 限定面/边/轴,再以几何签名评分,最后应用置信度和唯一性阈值。0 个候选报 selector_not_found,多个同分候选报 selector_ambiguous。两种情况都不能继续 strict rebuild。
原始 stable_id 不能被当作 OCC 持久名称。解析器必须输出候选、评分和最终原因,而不是隐藏地选择拓扑对象。
### 5.6 Fillet 与 chamfer
实现顺序为:edge selector、face selector 展开到边、单距离 chamfer、双距离或角度 chamfer、tangent propagation。tangent propagation 只能从已解析 edge 出发,沿当前 B-rep 中共享顶点且切向连续的 edge chain 扩展,不能退化为全局边集合。每次 OCC 修饰后都重新扫描 registry,因为此前 B-rep 对象可能失效。
不得提供“没有 selector 时对全部边应用”的回退。当前 550 个 chamfer 与 286 个 fillet feature 均没有 selector;这不是仅新增 runtime 函数就能解决的问题。它们必须由 converter/exporter 提供选择集,或由针对 source truth 的独立 selector enrichment pass 产生唯一、可审计的 selector,才可进入严格重建池。
### 5.7 Feature-level pattern
pattern_linear 和 pattern_mirror 重放 source feature 的语义执行定义,不复制完整 body,也不在 compiler 中仅平移三维坐标。每个实例有独立 transform scope,并通过相同 atomic executor 在当前 body 上执行。
- linear pattern 支持一维和二维 direction/spacing/count,并保留 direction reverse;
- mirror pattern 使用 canonical plane,支持显式 plane 或 registry reference;
- source feature 必须已成功执行,且其 selector/reference 经 transform 后仍可唯一解析;显式 host_face.frame 与局部孔位是可直接变换的坐标 contract,未显式 frame 的 host selector、dress-up selector 和 B 层终止 selector 在具备完整 transform contract 前必须阻断;
- 无 source feature、不可变换 selector 或布尔失败时,整个 pattern 阻断并给出实例级错误。
## 6. 数据补全责任
engine 负责执行确定的 CDSL,不负责虚构 source intent。下列数据问题必须由 exporter/converter 或可审计 enrichment pass 解决:
| 数据缺口 | 当前数量 | 所需动作 |
| --- | ---: | --- |
| Hole Wizard 缺少 semantic selections | 761 | 捕获 host face、placement frame 和位置关联 |
| 缺 source sketch parent | 153 | 记录草图 parent feature/reference plane |
| reference plane 朝向未捕获 | 21 | 导出 origin、normal、x direction 或稳定派生关系 |
| hole 直径或深度缺失 | 3 | 捕获原始尺寸及单位 |
| revolve 缺 selection 或 axis | 2 | 捕获 revolve axis/reference |
| fillet 尺寸无效 | 1 | 导出有效 radius/distance |
| chamfer 缺 semantic selections | 1 | 捕获 edge/face 选择集 |
部分 Hole Wizard 虽有 host_face,但其来自 source STEP 推断。enrichment pass 必须将其转换为可解析 selector contract,并在置信度不足时保留 unresolved。同一规则适用于 fillet/chamfer,不能为了提高覆盖率创造不稳定 ID。
## 7. 分阶段交付与覆盖目标
批量覆盖数字是静态“输入就绪池”,不是尚未实现内核下的通过率承诺。所有数字均要求无 unresolved、profile 限于本批四类、analytic_contours 仅含 line/arc/circle,且终止条件在当前阶段已支持。
| 阶段 | 交付物 | 阶段出口 | 静态就绪池 |
| --- | --- | --- | ---: |
| P0 | batch_rebuild、基线 manifest、feature 级报告 | 998 个输入均有机器可读结果;可复现首个阻断 feature | 998 |
| P1 | capability analyzer、execution session、reference plane/axis、校验修正 | 非草图 atomic 可规划;旧 deferred 不再是唯一阻断理由 | - |
| P2 | analytic_contours region resolver | line/arc/circle、洞与闭环测试通过 | - |
| P3 | unified extrude/revolve 与 A 层终止条件 | 基础实体池全部通过 runtime preflight,并以 truth 运行回归 | 266 current / 271 historical estimate |
| P4 | topology/selector registry 与 Hole Wizard | 有 position、唯一 host face 的孔可严格执行 | 309 current / 312 historical estimate |
| P5 | fillet/chamfer 和 selector enrichment 闭环 | 只接受唯一 selector;所有缺 selector 输入明确阻断 | 取决于 enrichment |
| P6 | linear/mirror feature replay | source feature、context、transform 和实例诊断完整 | 341 current / 343 historical estimate |
| P7 | B 层终止条件、剩余数据补全和回归收敛 | 633 个无 unresolved 零件按实际 feature 组合进入全量目标池 | 633 |
P3 的 271、P4 的 312 与 P6 的 343 都是初始导出统计的历史估计。按当前 998 份 CDSL 的严格闭合-region contract 复算后,P3/P4/P6 静态池分别为 266/309/341:差额来自仅 reference history 或 consumed profile 无闭合 region,不能由 runtime 补齐。P3 的 266 件中另有 4 件缺 captured extent reference 或 revolve axis,因而当前 strict runtime-eligible 为 262;P4/P6 当前 strict runtime-eligible 分别为 277/290,主要阻断是 threaded Hole、缺 active body/reference 及不可变换的 selector。它们不是简单相加。
运行时以 `phase_pools.select_static_phase_pool` 固化 P3/P4/P6 输入定义:无 `unresolved`、仅该阶段允许的 atomic、至少一个 primary feature,且所有 consumed sketch 都是四种可解析 profile 的闭合 region。静态池不代表每个 feature 的 selector/reference 已完整捕获;当前缺 axis、extent reference 或 history 中无 active body 的文件必须在 strict preflight 报具体 blocker,不能被计入 runtime-eligible。
剩余 365 个带 unresolved 的零件不能仅靠补 engine atomic 达到严格重建。P7 的目标是把每个零件归入“可通过数据补全解锁”或“当前证据不足”,而不是报告模糊失败。
## 8. 批量基准与 CI 门槛
新增单一入口,例如 backend/engine/cdsl_engine/batch_rebuild.py,接收 CDSL 目录、truth 目录和输出目录。每次运行至少产生:
manifest.json
parts/.report.json
parts/.step
summary-by-atomic.json
summary-by-blocker.json
每份报告包含:
part_id, cdsl_path, semantic_valid, runtime_eligible, compiled, built,
geometry_verified, topology_observed, first_blocker, feature_results,
unsupported_atomic_ids, unsupported_profile_types, unresolved_input,
selector_resolution, numeric_comparison, timings
报告还必须输出稳定的 failure_category:input_incomplete、selector_resolution、unsupported_capability、occ_execution_failure、geometry_mismatch 或 coordinate_frame_mismatch_candidate;geometry_verified 是唯一成功类别。未请求 --build 但已通过预检的报告标为 runtime_eligible_not_built,它是非终态,不是失败或 verified。该分类只归纳已有证据,不能将构建完成或坐标框候选计为 verified。
numeric_comparison 必须保留严格的 passed 判定,并把体积、面积、实体数及无序包围盒跨度均吻合、但绝对坐标框不吻合的情况标为 coordinate_frame_mismatch_candidate。该标记仅帮助定位 workplane/export frame 数据问题,不能替代 geometry_verified。
CI 分三层运行:
1. 单元与 contract 测试:每个 atomic executor、profile resolver、selector 歧义、extent 计算与 capability/schema 同步;
2. 小型集成 fixture:reference -> sketch -> primary feature -> dress-up/pattern 跨 feature 路径;
3. 批量回归:保存按零件和 atomic 分组的基线,禁止已验证零件退化,新增通过必须附带数值比对。
每次新增 atomic 或终止条件,必须同时更新 schema contract、capability registry、executor、诊断、单元测试和至少一个批量 fixture。不得只把名称加入 SUPPORTED_ATOMIC_IDS。
### 8.1 当前 P3 严格基线
2026-08-23 已按当前静态 P3 pool 运行以下 CDSL-only 基线;每个零件在独立进程中构建,单件 timeout 为 15 秒:
PYTHONPATH=backend/engine python -m cdsl_engine.batch_rebuild \
json_to_cdsl/output --out /tmp/cdsl-p3-current-baseline \
--phase p3 --build --build-timeout 15
最终结果为 266/266 已完成、262 份 strict runtime eligible、253 份 built、57 份 geometry verified。其余终态分类为 147 份 geometry_mismatch、49 份 coordinate_frame_mismatch_candidate、6 份 input_incomplete、5 份 occ_execution_failure、2 份 selector_resolution。这是一份验收基线而非成功率承诺:坐标框候选和已构建 STEP 均没有并入 verified。
该命令和输出目录结构是可恢复的;CI 应将经过审查的报告摘要保存在持久化工件中,而不依赖本机 /tmp 的 STEP 临时文件。
同日使用相同的 CDSL-only、每件 15 秒隔离构建策略完成 P4 池:309/309 已完成、277 份 strict runtime eligible、258 份 built、59 份 geometry verified。其余终态为 150 份 geometry_mismatch、49 份 coordinate_frame_mismatch_candidate、8 份 input_incomplete、5 份 occ_execution_failure、12 份 selector_resolution、26 份 unsupported_capability。P4 的 5 个 OCC 失败均已出现于 P3 基础主体能力池,未发现 Hole Wizard 新增的 OCC 失败。
P6 池也已使用同一策略完成:341/341 已完成、290 份 strict runtime eligible、268 份 built、60 份 geometry verified。其余终态为 159 份 geometry_mismatch、49 份 coordinate_frame_mismatch_candidate、9 份 input_incomplete、6 份 occ_execution_failure、14 份 selector_resolution、44 份 unsupported_capability。其中嵌套 pattern source 已按可回放 feature definition 递归执行;不能产生实体的 context source 会在 capability preflight 以 unsupported_pattern_source 阻断,不会再被归为 OCC 执行失败。
P7 的全量 capability 审计也已完成:998/998 份 CDSL 均有 machine-readable report,全部 semantic valid;290 份 strict runtime eligible(未请求 --build,因此分类为 runtime_eligible_not_built)、612 份 input_incomplete、96 份 unsupported_capability。这证明所有当前输入均被审计和分类,但不将 preflight 通过等同于 STEP 构建或 geometry verified。
## 9. 完成判定
本目标完成需要同时满足:
1. schema 已声明的 16 个 feature atomic 都有 executor、preflight contract 和 feature 级诊断;
2. analytic_contours 的 line/arc/circle 可构成带洞 region,并由统一 adapter 执行;
3. 266 个当前基础静态就绪零件均已由 phase-pool 回归审计;其中 262 个在现有输入下通过 strict runtime preflight,剩余 4 个以缺 axis/reference 的 feature-level blocker 报告;当前 CDSL-only P3 基线为 253 built、57 geometry verified,且所有非 verified 结果已有严格终态分类;
4. Hole、dress-up、pattern 与 selector-dependent extent 不再依赖 compiler 内特例或全局 build123d 状态;
5. 每个无法严格重建的零件都能区分为输入缺失、selector 歧义、未支持能力或 OCC 执行失败;
6. 批量报告和 CI 基线持续追踪 998 个输入,且 CDSL-only 成功路径不调用 legacy translator。
这样,engine 的扩展单位是可独立测试、可替换内核、可追溯失败原因的原子能力,而不是为某一批零件增加临时分支。