40 KiB
CADQL Tagging 与 Auto Semantics 重构设计
文档状态
- 状态:Partially implemented (bounded transition)
- 目标版本:Semantic Binding Schema 1.0
- 依赖:
design-docs/cadql-brep-query-language.md - 目标项目:SimpleCADAPI 2.x
- 主要影响模块:
tagging.py、autotag.py、core.py、topology.py、tracking.py、graph.py、serializer.py、cadql/、各 translator backend - 非目标:继续扩展当前
ql.py、为每种 feature 增加专用 selector、用 tag 替代完整 topology history
当前实现边界
当前 2.0 graph/model schema 已实现 Semantic Binding Schema 1.0 的 bounded subset:source-preserving TagBinding、local/inherited/effective/lineage scope、显式 downward policy、evidence-gated tracking projection、semantic-only graph node、model-level semantic_bindings registry 与 strict replay。当前 ql.py 仅作为过渡层增加 scoped tag predicate、typed operation/origin/output-role predicate,以及 projected source-binding/source-topology predicate,不是完整 CADQL Query IR。
尚未实现完整 typed CADQL Query IR、完整 Topology Evolution Graph、GraphQL-like parser、所有 topology/use 类型以及全部 translator backend parity。当前实现继续使用 graph/model schema 2.0;本文中依赖 schema 3.0 或完整 provider contract 的部分仍为 proposed。
已实现的 feature output role 子集
当前 TopoDelta.roles: Tuple[TopoRoleEntry, ...] 将 output role 与
TopoEntry.event 分开保存。每个 role entry 使用 geometry-node-owned durable
TopoRef,并要求 operation-owned OCC witness、coverage=complete、
status=proven 与 exact result membership。以下是当前 public contract:
| Operation | Role | Kind | Requested cardinality |
|---|---|---|---|
| Extrude | extrusion.start |
Face | exactly one |
| Extrude | extrusion.end |
Face | exactly one |
| Extrude | extrusion.side |
Face | at least one, bind all |
| Revolve | revolution.start |
Face | exactly one |
| Revolve | revolution.end |
Face | exactly one |
| Revolve | revolution.side |
Face | at least one, bind all |
| Fillet | fillet.patch |
Face | at least one, bind all |
| Chamfer | chamfer.patch |
Face | at least one, bind all |
| Shell | shell.body_face |
Face | at least one, bind all |
| Shell | shell.offset_face |
Face | at least one, bind all |
| Shell | shell.closing_descendant |
Face | at least one, bind all |
| Shell | shell.wall |
Edge | at least one, bind all |
| Loft | loft.start |
Face | exactly one |
| Loft | loft.end |
Face | exactly one |
| Loft | loft.side |
Face | at least one, bind all |
| Sweep | sweep.start |
Face | exactly one |
| Sweep | sweep.end |
Face | exactly one |
| Sweep | sweep.side |
Face | at least one, bind all |
这些 role 由 FirstShape、LastShape、Generated、Modified、Fillet/Chamfer
contour API 和 exact result membership 产生;不使用 center/normal、enumeration
index 或 unmatched-to-generated fallback。Public feature 的 named tag arguments
lower 为独立 apply_tag_rselection node,用户
binding 是 USER_OPERATION + ASSERTED,自动 role binding 是
AUTO_RULE + PROVEN + RECOMPUTE。Geometry node params 不保存这些 tag。
Strict replay 会重建 feature 后比较 serialized/recomputed role entries,并验证 role allowlist、feature node ownership、output slot、coverage/status、topology kind、binding ancestry、cardinality 和 exact selected refs。Full revolve 不具有 独立 start/end cap;OCC 未证明的 shell role 也保持 unavailable。调用方请求这些 role 时整个 operation 失败,不以 geometry guess 补齐。
当前 bounded QL 增加:
ql.output_role(role_name="extrusion.end")
ql.source_binding(binding_id="tag_binding_...")
ql.source_topology(topo_id="edge_...")
后两个 predicate 只查询 canonical local TagBinding.evidence。Extrude 的
source Edge 到 generated side Face 投影只复制完整 witness 下的 local
USER_OPERATION binding,并保存 source binding/topology、target topology、
operation、role 和 evidence method。Replay-safe authoring 必须把
apply_tag_rselection(...) 返回的 semantic view 作为 feature input;detached
semantic branch 不会引入隐藏 graph coupling。Predicate payload
deserialization 对 unknown kind、unknown/missing fields 与非法 child cardinality
fail closed。
1. 摘要
下一代 tagging 系统不再把所有语义压入 topology wrapper 上的 _tags: set[str]。Canonical truth 是可序列化、保留来源的 TagBinding;CADQL 将 tag 作为 semantic.tags 属性查询,并在执行时计算 local、inherited、effective 和 lineage 四种 scope。
Auto tagging 也不再表示“给所有结果实体补一些字符串”。它是一组 evidence-gated semantic rules:规则只能在所需事实可证明时产生 TagBinding,证据不足时产生 UNKNOWN/diagnostic 或不产生 assertion,不能把 unmatched entity 推断为 generated。
本设计遵循以下边界:
- 用户或产品域赋予的 unary categorical meaning 使用 tag。
- Current BRep 结构事实使用 topology property/relation。
- 数值、枚举、几何分类和诊断使用 typed property/metadata。
- Operation、source role、split/merge/generated/preserved 和多来源因果使用 Topology Evolution Graph。
- Tag 可以作为稳定意图锚点,但不能成为 relation、history 或 evidence 的损失性副本。
2. 当前问题
当前实现由四套机制叠加而成:
| 机制 | 例子 | 当前问题 |
|---|---|---|
| 用户显式 tag | role.mounting_surface |
与系统 tag 共用一个 set,无法识别作者和 assignment。 |
| Wrapper 结构 tag | wire.outer、edge.boundary |
把可直接从 BRep graph 得到的事实 materialize 为字符串。 |
| 几何分类 tag | face.top、face.side |
frame、算法和置信度不明确;未知几何退化为 enumeration index。 |
| Tracking tag | op.cut.generated、origin.tool |
把 Change event 和 source role 降级为 unary string,且依赖 Face-only matcher。 |
具体缺陷包括:
_tags: set[str]不保存 assignment、producer、target query、attachment、propagation、evidence 和 lifecycle。- Downward propagation 直接复制字符串,之后无法区分 local 与 inherited。
_carry_source_tags()直接复制 source Face 字符串,无法恢复 lineage witness。apply_tracking_tags()只遍历 Face,不能消费 Edge/Wire/TopoUse history。- Unmatched Face 默认被标记
generated,把 history 缺失伪装成确定事件。 - Boolean
section_edges是 Edge evidence,却用 Face ID 匹配,不能正确工作。 - Loft/sweep 提供 Edge history,但 Face-only auto tagger仍会给结果 Face生成看似完整的 operation tag。
- Transform 的 pure-preserve fallback 没有逐实体 correspondence,却对所有结果 Face声称 preserved。
face.face_0、pattern index 和 sketch edge zip-order 依赖 backend enumeration,不是 durable semantic identity。- Operation runtime 的 rich
delta_entries与 canonicalTopoDelta.entries分离,replay/translator 无法保证同一 semantic output。
当前测试中的“每个结果 Face 都有 operation tag”不是正确性证明,因为该覆盖率可以完全由 unmatched-to-generated fallback 产生。
3. 与 CADQL 的关系
CADQL 在三种图的联合视图上执行:
| 数据层 | 职责 | Tagging 是否拥有该事实 |
|---|---|---|
| Operation Graph | 模型构建、assignment producer、query binding | 否;TagBinding 引用它。 |
| Current BRep Graph | contains、boundary、incident、adjacent、TopoUse | 否;tag 只作为 entity 的 semantic property。 |
| Topology Evolution Graph | Change input/output、role、event、derivation | 否;lineage scope 依赖它计算。 |
| Semantic Binding Store | 用户/系统声明的稳定 unary meaning | 是。 |
CADQL 只有一种 tag predicate:
cadql.tag("role.mounting_surface", scope="effective")
它是对 semantic.tags 的 property predicate,不创建新的 selector、anchor 或 context 类型。Tag assignment 的 target 本身使用同一套 SelectionQuery[T];不再引入另一套 tag selector DSL。
4. 设计原则
4.1 一项事实只有一个 canonical owner
以下映射是强制的:
| 事实 | Canonical owner | 可否派生为 tag |
|---|---|---|
| Face 的 outer/inner loop | topology.loop_role |
默认否。 |
| Edge 是 Face boundary | boundary_uses/use_entity |
否。 |
| Surface 是 plane/cylinder | geometry.surface_type |
默认否。 |
| Face 当前在 world +Z 方向 | oriented geometry predicate + frame | 否。 |
| Entity 由某 operation 产生 | provenance.produced_by |
否。 |
| Entity 是 preserved/modified/generated | Change output event | 否。 |
| Entity 来自 body/tool/profile/path | Change input role/path | 否。 |
| 用户声明 mounting surface | TagBinding | 是,且这是 canonical truth。 |
| 业务规则证明某面是 sealing surface | TagBinding + rule evidence | 是。 |
| 长度、半径、pattern index | typed property/metadata | 否。 |
Tag materialized cache 可以为性能复制 relation/property 的结果,但必须标记为 derived cache、可丢弃且不能成为 replay truth。Semantic Binding Schema 1.0 不定义此优化。
CADQL 中的 semantic.role 和 semantic.group 是 registry-backed TagBinding projection,例如从 role.* 和 group.* bindings 得到结构化视图,不建立第二份 writable storage。semantic.material 等具有独立 schema、互斥或结构化值的属性使用 typed semantic property,不同时编码为 tag。查询 provider必须从同一个 canonical owner求值这些属性。
4.2 Tag 只表达 unary categorical semantics
适合 tag 的内容:
role.mounting_surface
role.sealing_surface
anchor.datum.primary
group.fasteners
process.inspect
不适合 tag 的内容:
op.make_cut_rsolid.generated
origin.tool
face.area.245
edge.index.3
face.normal.+z
wire.outer
判断标准:如果完整含义需要 source、target、operation、frame、单位、置信度或多个参与者,它就不是单个 tag。
4.3 Evidence 不足时保持未知
Auto semantic rule 的三值结果为:
PROVEN 所需 evidence 完整,允许发出 binding。
NOT_APPLICABLE 规则已完整求值,candidate 不满足。
UNKNOWN evidence 或 capability 不足,禁止发出 binding。
UNKNOWN 不能被实现为 false、generated、preserved 或最佳猜测。Strict replay 中,如果 feature 依赖该 auto semantic,UNKNOWN 必须产生结构化错误;非依赖型装饰 semantic 可以只生成 diagnostic。
4.4 Query intent 与 execution evidence 分离
Target query 描述要标记谁;assignment evidence 描述某次执行为何解析到这些 entities。Replay 先重新执行 query,再比较 evidence。TopoRef.topo_id 和 geometry fingerprint 只属于 evidence,不是 TagBinding identity。
4.5 Semantic state 是版本化 shape view
apply_tag_rselection 不修改 geometry,但产生新的 semantic state version。相同 BRep entity 在 assignment 前后可以有不同 effective tags。CADQL provider 必须相对当前 scope producer/version 读取 bindings,不能从全局 mutable wrapper set 读取历史无关的并集。
5. Canonical 数据模型
5.1 TagDefinition
Tag token 继续使用 normalized dot-token 格式:
[a-z][a-z0-9_-]*(.[a-z][a-z0-9_-]*)*
可选 registry 为已知 namespace 声明行为:
{
"tag": "role.mounting_surface",
"namespace": "role",
"value_kind": "categorical",
"allowed_target_types": ["face"],
"default_topology_propagation": "local",
"default_lineage_policy": "continuation_fragment"
}
Registry 用于 validation 和文档,不拥有 assignment。未注册但格式合法的 custom tag 可以被允许,但必须显式提供 propagation 和 lineage policy,不能从字符串前缀静默猜测。
5.2 TagBinding
Canonical assignment:
{
"schema_version": "1.0",
"binding_id": "tag_binding_mounting_surface",
"tag": "role.mounting_surface",
"producer": {
"kind": "user_operation",
"node_id": "node_tag_mounting_surface",
"rule_id": null,
"rule_version": null
},
"scope": {
"node_id": "node_body",
"output_slot": 0
},
"target": {
"kind": "selection_query",
"query_hash": "sha256:...",
"binding_hash": "sha256:..."
},
"attachment": "local",
"propagation": {
"topology": "local",
"lineage": "continuation_fragment"
},
"evidence": {
"kind": "query_execution",
"execution_hash": "sha256:...",
"selected_refs": []
},
"certainty": "asserted",
"lifecycle": "assertion"
}
字段语义:
| 字段 | Contract |
|---|---|
binding_id |
Assignment identity,不由 selected topology ID 生成。 |
tag |
Unary semantic token。 |
producer |
用户 operation 或 versioned auto rule。 |
scope |
Target query 的 current snapshot/version boundary。 |
target |
Canonical Query IR binding 或仅用于 legacy import 的 explicit refs。 |
attachment |
新 assignment 只允许 local;inherited 是计算结果。effective_legacy 仅用于迁移。 |
propagation.topology |
local 或显式 downward;local 表示不沿 topology传播。 |
propagation.lineage |
允许沿哪些 derivation 计算 lineage visibility。 |
evidence |
Assignment execution witness,不参与 query intent hash。 |
certainty |
asserted 或 proven;猜测值不能进入 canonical bindings。 |
lifecycle |
replay 时重新解析、重新计算或保持 legacy snapshot。 |
5.3 TargetBinding
新 assignment 的 target 必须是:
selection_query canonical Query IR + runtime bindings
scope_root lower 为选择当前 scope root 的 canonical query
以下 target 只用于迁移:
explicit_refs execution-local refs,无 semantic intent
legacy_effective 只有旧 flat tag snapshot
Auto rule 可以直接在 producer operation 的已知 Change outputs 上产生 target,但 serialization 时仍 lower 为 canonical source-preserving target:
- 引用 producer output variable 的 query;或
- 引用 versioned Change output set 的 internal binding。
不能只保存“当时第 3 个 Face”。
5.4 Producer
Producer kind:
user_operation
auto_rule
imported_sidecar
legacy_import
Auto rule 必须保存稳定 rule_id 和 rule_version。修改 rule 语义必须提升 version;replay 可据此检测 semantic drift。
5.5 Evidence
Evidence 是 tagged union:
| Kind | 必需内容 | 适用场景 |
|---|---|---|
user_assertion |
assignment node、authoring source | 用户明确声明。 |
query_execution |
query/binding/execution hash、selected refs | Query target assignment。 |
topology_change |
Change IDs、input/output witnesses、coverage | 基于 lineage 的 auto rule。 |
geometry_classification |
algorithm/version、frame、tolerance、measured properties | 几何分类规则。 |
imported_sidecar |
source URI/hash/schema | 外部 semantic data。 |
legacy_snapshot |
imported tags、migration diagnostic | 旧模型兼容。 |
Evidence 可以证明 assignment,但不会把几何 fingerprint 升级为 durable target identity。
6. Tag Scope 的正式语义
6.1 Local
local 返回当前 semantic state version 中,target query 直接匹配该 entity/use 的 bindings。
local(e, v) = {b.tag | binding b is visible in semantic version v
AND target(b, v) contains e}
它不包含 topology parent、model entity 或 lineage ancestor 的 tag。
6.2 Inherited
inherited 只来自显式 topology propagation policy:
inherited(e, v) = bindings attached to ancestor a
where topology propagation is downward
and contains-path(a, e) is valid in snapshot v
规则:
- 不再根据
role.*、anchor.*、group.*前缀自动决定传播。 - Propagation 在 assignment 时显式冻结并序列化。
- Downward 传播计算于 Current BRep containment,不复制字符串。
- 默认是
local,即不传播。 - 给 Solid 标记
role.mounting_plate不应默认让每条 Edge 都成为 mounting plate。 - 若确实表达 assembly/model membership,优先使用 model relation 或显式 group binding;不要依靠 topology descendants 模拟产品结构。
6.3 Effective
effective(e, v) = local(e, v) union inherited(e, v)
effective 不自动包含 lineage。这样 current snapshot 内的 attachment semantics 与跨 operation ancestry 保持正交。
6.4 Lineage
lineage 通过 TagBinding 与 Topology Evolution Graph 联合计算:
lineage(e, v) = source bindings whose tagged entities are reachable
through allowed Change output derivations
默认 policy:
| Policy | 允许 derivation | 说明 |
|---|---|---|
none |
无 | 不跨 operation 可见。 |
continuation |
CONTINUATION |
只接受同角色延续。 |
continuation_fragment |
CONTINUATION、FRAGMENT |
允许 trim/split fragments。 |
explicit |
assignment 指定集合 | 允许 MERGE/REPLACEMENT 等业务定义。 |
INTERSECTION 和 BOUNDARY 默认不继承 source tag,因为新 entity 是由 source 参与生成,不等于 source 语义角色的延续。需要选择这类结果时使用 generated_from、depends_on 或 cadql.change(...)。MERGE/REPLACEMENT 也不默认继承,除非 assignment 显式声明。
lineage scope 只返回 lineage-derived tags;调用方若需要本地与 lineage 并集,应显式组合 predicates,不把 effective 的含义扩大。
History capability 为 NONE 或所需 path evidence 不完整时,请求 lineage 必须产生 UnsupportedQueryCapabilityError,不能返回空集冒充“没有 tag”。
6.5 TopoUse
TagBinding 可以 target entity 或 oriented use:
- Entity tag 对同一 underlying entity 的所有 occurrences 可见。
- TopoUse tag 只对该 parent/orientation/occurrence 可见。
- TopoUse 的 inherited 与 lineage 依赖 use-level containment/evolution evidence。
- 缺少 use ancestry 时不能把 entity lineage tag 冒充 occurrence lineage tag。
7. Public API 与 Operation Graph
7.1 用户赋值
保留简单入口:
apply_tag(body, "role.mounting_plate")
新 schema 中该 convenience API 的固定默认值是:
topology_propagation = LOCAL
lineage_policy = CONTINUATION_FRAGMENT
因此它不会把 Solid 的 role 复制给所有 Face/Edge,但在 backend 提供完整 CONTINUATION/FRAGMENT evidence 时,该 assertion 可以通过 scope="lineage" 从后续版本查询。需要 topology downward inheritance 时必须调用带显式 policy 的 apply_tag_rselection。迁移期执行旧 model时可以保留旧 effective结果,但新 assignment不能继续按token prefix选择policy。
它 lower 为 scope-root query 和 canonical operation:
apply_tag_rselection(
scope: Shape<K>,
targets: SelectionSet<T>,
tag: Tag,
topology_propagation: LOCAL | DOWNWARD,
lineage_policy: NONE | CONTINUATION | CONTINUATION_FRAGMENT | EXPLICIT,
) -> Shape<K>
推荐的精确赋值:
mounting_face = (
cadql.select(cadql.Face, in_=body)
.where(
cadql.surface_type.eq("plane")
& cadql.normal.same_direction_as(
(0, 0, 1),
relative_to=body,
angle_tolerance=cadql.deg(0.1),
)
)
.expect_one()
)
tagged_body = apply_tag_rselection(
body,
targets=mounting_face,
tag="role.mounting_surface",
topology_propagation="local",
lineage_policy="continuation_fragment",
)
Active GraphSession 必须记录 target Query IR 和 binding,不能只记录 resolved Face refs。
7.2 读取
CADQL 是 canonical query API:
cadql.select(cadql.Face, in_=body).where(
cadql.tag("role.mounting_surface", scope="effective")
)
list_tags(shape) 可以保留为 current wrapper convenience,但默认返回当前 version 的 effective tags,并应允许显式 scope:
list_tags(shape, scope="local")
list_tags(shape, scope="effective")
list_tags(shape, scope="lineage")
它不得绕过 provider 从 _tags 直接读取。迁移期旧签名等价于 scope="effective"。
7.3 删除和替换
Tag 删除不是从 entity set 中 discard() 字符串,而是产生新的 semantic operation,撤销或 supersede 指定 binding:
remove_tag_rselection(scope, targets, tag, matching_producer?) -> Shape<K>
默认不能静默删除其他 producer 的同名 binding。例如移除 auto-rule binding 不应删除用户 assertion。
7.4 Conflict semantics
同一个 entity 可同时存在多个 producer 的同名 tag,查询结果按 token 去重,但 evidence/projection 保留所有 bindings。
Tag 1.0 不定义基于命名约定的互斥,例如 state.open 与 state.closed。真正互斥的数据应使用 typed enum property。若产品域 registry 声明 tag group 互斥,assignment validation 必须报告 conflict,不能按“最后写入者获胜”处理。
8. Auto Semantics Rule Contract
8.1 Rule schema
每条规则必须声明:
{
"rule_id": "simplecad.primitive.box.face_roles",
"rule_version": "1.0",
"trigger": "make_box_rsolid",
"candidate_type": "face",
"required_capabilities": [
"operation_output_roles",
"oriented_face_geometry"
],
"required_evidence": {
"history": "operation_native",
"frame": "operation_context",
"coverage": "complete"
},
"output": {
"kind": "tag_binding",
"allowed_tags": ["role.cap.start", "role.cap.end", "role.side"]
},
"unknown_policy": "diagnostic",
"lifecycle": "recompute"
}
Rule evaluator 返回:
bindings
status: PROVEN | NOT_APPLICABLE | UNKNOWN
evidence
diagnostics
coverage
8.2 权威等级
| Level | Source | 可产生的结果 |
|---|---|---|
| 1 | 用户显式 assertion/imported authoritative sidecar | certainty=asserted binding。 |
| 2 | Kernel/operation-native topology history | Change graph;满足业务规则时可产生 certainty=proven binding。 |
| 3 | Exact current topology fact | topology property/relation;通常不 materialize 为 tag。 |
| 4 | Deterministic geometry classifier | typed geometry property;只有注册业务映射后才能产生 tag。 |
| 5 | Heuristic/fingerprint | diagnostic/evidence only。 |
低等级 evidence 不能覆盖或伪装为高等级事实。尤其 geometry proximity 不能产生 preserved/generated lineage。
8.3 Coverage
每个 rule evaluation 必须声明:
COMPLETE 候选 universe 与所需 evidence 完整。
PARTIAL 只有部分 candidates/relations 有 evidence。
NONE 无法求值。
只有 COMPLETE 且 rule 对具体 candidate 得到 PROVEN 时才发出需要全局排他性的 tag,例如“唯一 start cap”。PARTIAL 不能通过给其余 candidates 标记 opposite role 来补齐结果。
8.4 禁止行为
以下规则在新系统中非法:
- unmatched result entity =>
generated。 - pure-preserve delta => 所有 result entities preserved,而无逐实体 mapping。
- backend enumeration index => semantic tag。
- geometry look-alike => lineage continuation。
- 将 operation 名、event 和 origin role拼接为 tag作为唯一事实。
- 给所有 descendants 无条件复制
role.*。 - 多来源 Change => 只保留一个
origin.*字符串。 - rule 失败后静默回退到 fingerprint 并仍标记
proven。
9. Operation-by-Operation 策略
9.1 Primitive
Primitive operation 自己知道构造参数和 output roles,优先使用 operation-native evidence,而不是事后猜测几何。
| 当前输出 | 新 canonical 表达 |
|---|---|
geom.primitive.box |
provenance.operation_type == make_box_rsolid 或 typed semantic metadata,不需要 tag。 |
裸 box |
删除。 |
face.top/bottom/front/... |
不自动作为 world-direction tag。使用 geometry predicate + explicit frame。 |
face.surface |
geometry.surface_type。 |
如果产品 API 需要稳定 feature role,可定义 frame-aware operation role:
role.cap.start
role.cap.end
role.side
这些角色必须绑定 primitive 的参数方向和 operation context,并保存 rule evidence。对于 box 的四个侧面,如果没有额外业务区别,不自动命名 front/back/left/right;数学对称性应保留为集合。
Cone 必须与 cylinder 使用同一 role contract,不再因为当前实现遗漏 auto_tag_faces() 而表现不同。
9.2 Extrude 和 Revolve
Feature provenance 和 topology evolution进入 Change graph:
- Profile Face/Coedge 是
subject或supportinput。 - Start/end continuation、side/boundary outputs使用 event + derivation表示。
face.extrusion.start/side/end若保留为用户友好 semantic,必须由 operation-native role mapping产生 TagBinding,不使用 center exact equality或 normal exact equality。solid.extrusion改为provenance.operation_type,不作为 tag。- Revolve 使用相同 Change contract;full/partial revolve 的 caps必须按实际 operation evidence处理。
推荐 query:
side_faces = (
cadql.select(cadql.Face, in_=extruded)
.where(
cadql.related(
cadql.generated_from,
from_=cadql.this,
to=profile_boundary,
derivations=("boundary",),
depth=1,
)
)
)
只有业务代码确实需要可命名的 feature role 时才额外发出 role.extrusion.side。
9.3 Boolean
Boolean 不再产生 canonical op.* 或 origin.* tags。
必须记录:
- 每个 operand 的 named input port。
- 每个 source entity 的 role:
subject、tool、support或context。 - 每个 output entity 的 event 和 derivation。
- Intersection Edge 的多 source Change witness。
交界 edge 使用:
cadql.change(
inputs=(
cadql.change_input(subject_faces, input_port="subjects", role="support"),
cadql.change_input(tool_faces, input_port="tools", role="tool"),
),
output=cadql.this,
derivation="intersection",
)
不能用 role.section_face 替代 Edge-level INTERSECTION Change。若产品域确实定义“section interface”业务角色,可在上述 query 上显式应用 tag;该 tag 的 target intent仍是 Change pattern。
多步 cut/intersect 必须保留每一步 Change,不能简单拼接 event buckets 后覆盖相同 topo_id 的 delta_entries。
9.4 Fillet、Chamfer 和 Shell
这些 feature 的核心是 target selection 与 Change graph:
- 用户选择的 Edge/Face 是
targetinput。 - 邻接 support Face 是
supportinput。 - Trimmed source entities 是
CONTINUATION/FRAGMENToutput。 - Transition Face 和新 boundary Edge 是
BOUNDARYoutput。 - 完全消耗的 source entity保留为 historical input与
DELETEDoutput event。
默认不产生 op.fillet.generated 等 tag。查询 transition geometry 应使用 generated_from、depends_on 和 co_result_of。
用户已有 role.mounting_surface 的 source Face,只沿 CONTINUATION/FRAGMENT 进入 lineage scope;fillet transition Face 不自动继承该角色。
9.5 Transform 和 Mirror
Rigid transform 不改变 topology role,但必须提供逐 entity/use CONTINUATION mapping。只有 mapping complete 时 lineage tag 才可查询。
solid.transform.mirrored改为 provenance/operation property。- 不复制 source wrapper
_tags。 - Mirror 的 orientation-sensitive TopoUse/normal 必须在新 parent occurrence和 frame中重新求值。
- 没有逐实体 mapping 时 history capability 为
PARTIAL,不能把所有 Face声明 preserved。
9.6 Loft 和 Sweep
Loft/sweep 必须首先修复 evidence kind mismatch:
- Profile/path Edge history进入 Change graph。
- Result Face/Edge 与 profile/path source的关系必须由 operation-native adapter提供。
- Auto semantic evaluator按 candidate type消费对应 Change outputs,不允许 Face-only fallback。
- Profile 与 path 是不同 input ports/roles,不能把二者 tags union到 result Solid后丢失来源。
如果 backend只能提供 Edge-level partial history,Face lineage query与依赖它的 auto rule必须报告 unsupported/unknown;不能给全部 Faces标记 generated。
9.7 Pattern
Pattern 应有显式 Pattern operation 和 instance output relation:
source EntityVersion -> Change(instance identity) -> instance EntityVersion
每个 instance 保存稳定 operation-local instance_key,index只作为 typed property:
provenance.pattern_instance_key
provenance.pattern_ordinal
solid.pattern.linear/radial 改为 operation provenance,不是 semantic tag。Source tags通过 CONTINUATION lineage policy可见;不要复制到每个 instance wrapper。
对完全对称的 instances,若没有用户 tag或业务 key,CADQL返回集合或 ambiguity,不用 ordinal伪造 semantic identity。
9.8 Sketch Promotion
Sketch entity到 BRep Edge的映射是 source binding,不是 tag naming问题:
- Sketch entity/profile使用稳定 semantic refs。
- Promotion adapter记录每个 output Edge对应的 source entity ref和 evidence。
sketch.*、sketch_profile.*、sketch_entity.*不再作为唯一 mapping。- 禁止仅通过
zip(edges, entity_ids)声称 correspondence。 - 用户附着在 sketch entity上的 semantic tag可通过 proven promotion Change在
lineagescope查询。
10. Topology、Geometry、Provenance 与 Tag 的迁移表
| 现有 tag/数据 | 新位置 | 迁移行为 |
|---|---|---|
wire.outer/wire.inner |
topology.loop_role on WireUse/Coedge |
不导入为 semantic tag。 |
edge.boundary |
boundary_uses + use_entity |
不导入为 semantic tag。 |
face.top/bottom/... |
Legacy effective tag;新模型使用 frame-aware geometry query或 explicit role binding | 导入并警告方向语义未声明。 |
face.face_N |
Legacy enumeration annotation | 不生成新 binding;仅保留 migration evidence。 |
geom.primitive.* |
provenance.operation_type/typed metadata |
可保留 legacy effective,不再新发出。 |
op.<op>.<event> |
Change output event + performed_by Operation | 不生成新 binding。 |
origin.<role> |
Change input role/path | 不生成新 binding。 |
solid.boolean.* |
Operation provenance | 不生成新 binding。 |
solid.pattern.* |
Pattern provenance/property | 不生成新 binding。 |
role.* 用户 tag |
TagBinding | 尽可能恢复 assignment;否则 effective_legacy。 |
anchor.* 用户 tag |
TagBinding | 同上。 |
group.* 用户 tag |
TagBinding 或 model membership relation | 按 domain schema迁移。 |
| Numeric/index tags | typed metadata/property | 不作为 semantic binding。 |
11. Legacy 兼容
旧模型只有 flat tags时,导入为:
{
"producer": {"kind": "legacy_import"},
"target": {"kind": "legacy_effective", "refs": []},
"attachment": "effective_legacy",
"propagation": {"topology": "local", "lineage": "none"},
"certainty": "asserted",
"lifecycle": "snapshot",
"evidence": {"kind": "legacy_snapshot"}
}
Provider 只把 effective_legacy 暴露给 scope="effective"。它不能回答 local、inherited 或 lineage,并产生 migration diagnostic;该 attachment不是正常assignment可写入的值。
兼容规则:
- 旧 public
list_tags()继续看到原 effective tokens。 - 旧 QL tag predicate可由 adapter lower 为 CADQL
effectivepredicate。 - 不从 token prefix反推旧 propagation。
- 不从
op.*/origin.*反向构造可信 Change graph。 - 如果 graph中同时有真实 TopoDelta evidence,可以独立迁移为 Change;仍不能仅依据旧 tag补齐缺失 parent mapping。
12. Serialization 与 Provider Contract
Model schema 3.0 增加:
semantic_bindings: TagBinding[]
semantic_rules: AutoSemanticRuleRef[]
semantic_diagnostics: SemanticDiagnostic[]
Operation node可以引用其产生的 binding IDs。TagBinding target query复用 model顶层 query_objects,不嵌入语义缩水的第二份 query。
Provider 增加:
class SemanticProvider(Protocol):
def bindings(self, scope_version, entity_or_use) -> Sequence[TagBinding]: ...
def tags(self, entity_or_use, scope: TagScope) -> Sequence[str]: ...
def explain_tag(self, entity_or_use, tag: str, scope: TagScope) -> Sequence[TagWitness]: ...
explain_tag() 至少返回:
binding_id
producer
attachment path
topology inheritance path, if any
lineage Change path, if any
evidence status
diagnostics
OCP 和 FreeCAD provider必须运行同一 scope和rule conformance suite。Backend不支持某 rule所需 capability时报告 unknown/unsupported,不自行更换算法。
13. Invalidation 与 Replay
TagBinding lifecycle:
| Lifecycle | Replay behavior |
|---|---|
recompute |
重跑 target query或auto rule,生成新 evidence并比较 drift。 |
assertion |
重跑 target query;用户 semantic保留,但 query不再满足时失败。 |
snapshot |
仅 legacy/import sidecar;不能声称动态 lineage。 |
参数变化后:
- 重建 geometry和 Change graph。
- 重新解析 assignment target query。
- 重新运行 versioned auto rules。
- 撤销本次 replay中不再 proven的 derived bindings。
- 比较旧/新 evidence并生成 drift diagnostic。
- Feature依赖的 semantic target违反 cardinality时按 CADQL错误模型失败。
Derived auto binding不能因为曾经写入 wrapper set而永久残留。Semantic state由当前有效 bindings重新计算,不执行增量字符串清理猜测。
14. 错误与诊断
新增结构化错误:
| Error | 条件 |
|---|---|
TagValidationError |
token、target type、policy或registry不合法。 |
TagTargetResolutionError |
Assignment target query无法满足 cardinality。 |
SemanticConflictError |
Registry定义的互斥 semantic同时成立。 |
AutoSemanticEvidenceError |
Strict dependency所需rule evidence为UNKNOWN/PARTIAL。 |
SemanticCapabilityError |
Provider不能计算请求的tag scope或rule。 |
SemanticDriftError |
Strict replay中assignment/rule结果发生不允许的漂移。 |
Diagnostic 至少包含:
binding_id/rule_id
scope version
required and available capability
coverage
candidate count
missing witnesses
repair suggestions
15. 测试策略
15.1 Binding tests
- TagBinding JSON round-trip和stable hash。
- 同名tag、不同producer不会互相覆盖。
- Target query intent与execution refs分离。
- Remove/supersede只影响指定binding。
15.2 Scope tests
- local不包含parent和lineage tags。
- inherited只沿显式downward policy计算。
- effective严格等于local union inherited。
- lineage只沿允许的derivations计算。
BOUNDARY/INTERSECTION默认不继承source role tag。- history缺失时lineage产生capability error而不是空结果。
- entity tag和TopoUse tag保持不同visibility。
15.3 Auto rule precision/recall
- 每个emitted binding有required evidence witness。
- 可证明的semantic不会遗漏。
- Unmatched candidate不会得到generated/preserved tag。
- Partial coverage不会产生排他性role。
- Rule version变化产生semantic drift diagnostic。
15.4 Operation fixtures
- Primitive roles使用operation frame,不依赖world axis或Face枚举。
- Extrude/revolve caps和sides使用operation-native mapping。
- Boolean interface保留多input Change,Edge evidence不被当作Face。
- Fillet/chamfer source fragments、transition Faces和boundaries可通过evolution relation选择。
- Transform/mirror有逐entity continuation mapping。
- Loft/sweep在只有Edge evidence时拒绝Face lineage assertion。
- Pattern instances保留source lineage和instance key,不以ordinal作为semantic identity。
- Sketch promotion不依赖zip/enumeration order。
15.5 Replay与translator
- OCP和FreeCAD的tag scopes一致。
- Model JSON round-trip后producer/evidence/policies不丢失。
- 参数变化后过期auto bindings消失。
- Legacy effective tags仍可查询,但local/inherited/lineage明确unsupported。
16. 实施阶段
Phase A:Characterization 与止损
- 锁定当前public tag行为和serialized fixtures。
- 给unmatched-to-generated、section Edge/Face mismatch、loft/sweep mismatch增加failing characterization tests。
- 停止新增
op.*、origin.*和enumeration-derived tags。 apply_tracking_tags()增加diagnostic mode,逐步取消unsound fallback。
退出标准:所有已知误报都有测试,不再扩大flat-tag contract。
Phase B:Semantic Binding Schema
- 实现TagBinding、producer、target、policy、evidence和serialization。
- 实现semantic state version与binding store。
apply_tag_rselection记录target Query IR。- Flat
_tags暂时作为effective cache,不再是canonical truth。
退出标准:用户assignment可JSON round-trip并解释来源。
Phase C:CADQL Scope Provider
- 实现local/inherited/effective。
- 移除prefix-driven runtime copying;迁移为binding-time explicit policy。
- 实现
explain_tag()。 - Legacy tags仅通过effective adapter暴露。
退出标准:三个current-snapshot scopes通过OCP conformance tests。
Phase D:Topology Evolution Graph
- 按CADQL设计建立完整Change inputs/outputs。
- 将
delta_entries合并进canonical序列化schema。 - 修复Face-only consumer、section Edge、transform correspondence和多步Change。
- 实现lineage scope与history capability validation。
退出标准:continuation/fragment/boundary/intersection fixtures可查询且缺证据时失败。
Phase E:Auto Semantic Rules
- 引入versioned rule registry和三值求值。
- 先迁移primitive与extrude roles,再迁移其他feature。
- 删除unmatched-generated和operation/origin tags的canonical生成。
- Geometry heuristic仅作为typed property或diagnostic。
退出标准:每个auto binding都有rule、evidence、coverage和replay lifecycle。
Phase F:Translator 与清理
- FreeCAD provider实现相同semantic binding/scope contract。
- 更新docs、skills和examples到CADQL tag query。
- Deprecate
Solid.auto_tag_faces()和内部直接_tags复制。 - 删除flat tag作为truth的代码路径。
退出标准:OCP/FreeCAD semantic conformance一致,新model不依赖flat tags。
17. 推荐决策
- 采用
TagBinding作为唯一canonical tag assignment;_tags只能是迁移期effective cache。 - Tag仅表达用户/业务域的unary categorical semantics。
wire.outer、edge.boundary迁移到Current BRep properties/relations。op.*、origin.*、preserved/modified/generated迁移到Operation/Topology Evolution Graph。- 几何类型、方向、数值和pattern ordinal迁移到typed properties,不再自动materialize为tag。
- Downward propagation默认关闭并在每个binding中显式保存;不再按prefix复制字符串。
effective = local union inherited;lineage保持独立scope并依赖完整Change evidence。- Lineage默认只允许
CONTINUATION/FRAGMENT;BOUNDARY、INTERSECTION、MERGE和REPLACEMENT不自动继承semantic role。 - Auto semantics使用versioned、evidence-gated、三值规则;
UNKNOWN是一等结果。 - 立即禁止unmatched => generated、enumeration => semantic role、geometry guess => proven history。
- 所有tag target复用
cadql.select(...)和Query IR,不建设第二套selector或anchor API。 - Replay和translator必须保存并解释assignment intent、producer、scope、evidence和drift,不能只搬运最终字符串集合。
这套策略的核心不是让auto tagging覆盖更多实体,而是让每个可查询semantic都有明确作者、目标意图、适用scope、证明依据和失效规则。CADQL负责查询这些事实;Current BRep Graph和Topology Evolution Graph负责证明结构与历史;TagBinding只负责承载真正的semantic assertion。